diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json
index 4fac84c..e9fe339 100755
--- a/src/core/config/Categories.json
+++ b/src/core/config/Categories.json
@@ -86,6 +86,8 @@
"Bifid Cipher Decode",
"Affine Cipher Encode",
"Affine Cipher Decode",
+ "A1Z26 Cipher Encode",
+ "A1Z26 Cipher Decode",
"Atbash Cipher",
"Substitute",
"Derive PBKDF2 key",
diff --git a/src/core/operations/A1Z26CipherDecode.mjs b/src/core/operations/A1Z26CipherDecode.mjs
new file mode 100644
index 0000000..2a9f9ce
--- /dev/null
+++ b/src/core/operations/A1Z26CipherDecode.mjs
@@ -0,0 +1,63 @@
+/**
+ * @author Jarmo van Lenthe [github.com/jarmovanlenthe]
+ * @copyright Crown Copyright 2018
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation";
+import Utils from "../Utils";
+import {DELIM_OPTIONS} from "../lib/Delim";
+import OperationError from "../errors/OperationError";
+
+/**
+ * A1Z26 Cipher Decode operation
+ */
+class A1Z26CipherDecode extends Operation {
+
+ /**
+ * A1Z26CipherDecode constructor
+ */
+ constructor() {
+ super();
+
+ this.name = "A1Z26 Cipher Decode";
+ this.module = "Ciphers";
+ this.description = "Converts alphabet order numbers into their corresponding alphabet character.
e.g. 1
becomes a
and 2
becomes b
.";
+ this.infoURL = "";
+ this.inputType = "string";
+ this.outputType = "string";
+ this.args = [
+ {
+ name: "Delimiter",
+ type: "option",
+ value: DELIM_OPTIONS
+ }
+ ];
+ }
+
+ /**
+ * @param {string} input
+ * @param {Object[]} args
+ * @returns {string}
+ */
+ run(input, args) {
+ const delim = Utils.charRep(args[0] || "Space");
+
+ if (input.length === 0) {
+ return [];
+ }
+
+ const bites = input.split(delim);
+ let latin1 = "";
+ for (let i = 0; i < bites.length; i++) {
+ if (bites[i] < 1 || bites[i] > 26) {
+ throw new OperationError("Error: all numbers must be between 1 and 26.");
+ }
+ latin1 += Utils.chr(parseInt(bites[i], 10) + 96);
+ }
+ return latin1;
+ }
+
+}
+
+export default A1Z26CipherDecode;
diff --git a/src/core/operations/A1Z26CipherEncode.mjs b/src/core/operations/A1Z26CipherEncode.mjs
new file mode 100644
index 0000000..d1202d8
--- /dev/null
+++ b/src/core/operations/A1Z26CipherEncode.mjs
@@ -0,0 +1,61 @@
+/**
+ * @author Jarmo van Lenthe [github.com/jarmovanlenthe]
+ * @copyright Crown Copyright 2018
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation";
+import Utils from "../Utils";
+import {DELIM_OPTIONS} from "../lib/Delim";
+
+/**
+ * A1Z26 Cipher Encode operation
+ */
+class A1Z26CipherEncode extends Operation {
+
+ /**
+ * A1Z26CipherEncode constructor
+ */
+ constructor() {
+ super();
+
+ this.name = "A1Z26 Cipher Encode";
+ this.module = "Ciphers";
+ this.description = "Converts alphabet characters into their corresponding alphabet order number.
e.g. a
becomes 1
and b
becomes 2
.
Non-alphabet characters are dropped.";
+ this.infoURL = "";
+ this.inputType = "string";
+ this.outputType = "string";
+ this.args = [
+ {
+ name: "Delimiter",
+ type: "option",
+ value: DELIM_OPTIONS
+ }
+ ];
+ }
+
+ /**
+ * @param {string} input
+ * @param {Object[]} args
+ * @returns {string}
+ */
+ run(input, args) {
+ const delim = Utils.charRep(args[0] || "Space");
+ let output = "";
+
+ const sanitizedinput = input.toLowerCase(),
+ charcode = Utils.strToCharcode(sanitizedinput);
+
+ for (let i = 0; i < charcode.length; i++) {
+ const ordinal = charcode[i] - 96;
+
+ if (ordinal > 0 && ordinal <= 26) {
+ output += ordinal.toString(10) + delim;
+ }
+ }
+ return output.slice(0, -delim.length);
+ }
+
+}
+
+export default A1Z26CipherEncode;
diff --git a/test/tests/operations/Ciphers.mjs b/test/tests/operations/Ciphers.mjs
index fdc98a3..a46f50a 100644
--- a/test/tests/operations/Ciphers.mjs
+++ b/test/tests/operations/Ciphers.mjs
@@ -110,6 +110,39 @@ TestRegister.addTests([
}
],
},
+ {
+ name: "A1Z26 Encode: normal",
+ input: "This is the test sentence.",
+ expectedOutput: "20 8 9 19 9 19 20 8 5 20 5 19 20 19 5 14 20 5 14 3 5",
+ recipeConfig: [
+ {
+ op: "A1Z26 Cipher Encode",
+ args: ["Space"]
+ }
+ ],
+ },
+ {
+ name: "A1Z26 Decode: normal",
+ input: "20 8 9 19 9 19 20 8 5 20 5 19 20 19 5 14 20 5 14 3 5",
+ expectedOutput: "thisisthetestsentence",
+ recipeConfig: [
+ {
+ op: "A1Z26 Cipher Decode",
+ args: ["Space"]
+ }
+ ],
+ },
+ {
+ name: "A1Z26 Decode: error",
+ input: "20 8 9 27",
+ expectedOutput: "Error: all numbers must be between 1 and 26.",
+ recipeConfig: [
+ {
+ op: "A1Z26 Cipher Decode",
+ args: ["Space"]
+ }
+ ],
+ },
{
name: "Atbash: no input",
input: "",