|
4 | 4 | * @see - [wiki](https://en.wikipedia.org/wiki/Caesar_cipher)
|
5 | 5 | * @param {string} str - string to be encrypted
|
6 | 6 | * @param {number} rotation - the number of rotation, expect real number ( > 0)
|
| 7 | + * @param {string} [alphabet='abcdefghijklmnopqrstuvwxyz'] - Optional parameter to specify a custom alphabet |
7 | 8 | * @return {string} - decrypted string
|
8 | 9 | */
|
9 |
| -const caesarCipher = (str, rotation) => { |
| 10 | +const caesarCipher = (str, rotation, alphabet = 'abcdefghijklmnopqrstuvwxyz') => { |
10 | 11 | if (typeof str !== 'string' || !Number.isInteger(rotation) || rotation < 0) {
|
11 |
| - throw new TypeError('Arguments are invalid') |
| 12 | + throw new TypeError('Arguments are invalid'); |
12 | 13 | }
|
13 | 14 |
|
14 |
| - const alphabets = new Array(26) |
15 |
| - .fill() |
16 |
| - .map((_, index) => String.fromCharCode(97 + index)) // generate all lower alphabets array a-z |
| 15 | + const alphabets = Array.from(alphabet); // Allow custom alphabet |
| 16 | + const alphabetLength = alphabets.length; |
17 | 17 |
|
18 |
| - const cipherMap = alphabets.reduce( |
19 |
| - (map, char, index) => map.set(char, alphabets[(rotation + index) % 26]), |
20 |
| - new Map() |
21 |
| - ) |
| 18 | + // Optimize rotation to handle rotations greater than alphabet length |
| 19 | + const effectiveRotation = rotation % alphabetLength; |
| 20 | + |
| 21 | + // Create cipher map to avoid recalculating for each character |
| 22 | + const cipherMap = alphabets.reduce((map, char, index) => { |
| 23 | + map.set(char, alphabets[(effectiveRotation + index) % alphabetLength]); |
| 24 | + return map; |
| 25 | + }, new Map()); |
22 | 26 |
|
23 | 27 | return str.replace(/[a-z]/gi, (char) => {
|
24 |
| - if (/[A-Z]/.test(char)) { |
25 |
| - return cipherMap.get(char.toLowerCase()).toUpperCase() |
| 28 | + const isUpperCase = /[A-Z]/.test(char); |
| 29 | + const lowerChar = char.toLowerCase(); |
| 30 | + |
| 31 | + // Check if the character is in the map (i.e., an alphabetic character) |
| 32 | + if (cipherMap.has(lowerChar)) { |
| 33 | + const cipheredChar = cipherMap.get(lowerChar); |
| 34 | + return isUpperCase ? cipheredChar.toUpperCase() : cipheredChar; |
26 | 35 | }
|
27 | 36 |
|
28 |
| - return cipherMap.get(char) |
29 |
| - }) |
30 |
| -} |
| 37 | + // Return non-alphabetic characters unchanged |
| 38 | + return char; |
| 39 | + }); |
| 40 | +}; |
| 41 | + |
| 42 | +// Example usage: |
| 43 | +console.log(caesarCipher('Hello World!', 3)); // Khoor Zruog! |
31 | 44 |
|
32 |
| -export default caesarCipher |
| 45 | +export default caesarCipher; |
0 commit comments