DEV Community

Sergey Korsik
Sergey Korsik

Posted on

Refactoring. RegExp.

Hi! Today we will take a look on the competition between reg exps or.. their non-existence.

Atbash Cipher

Let's take a look on a quite interesting, but still simple task - to write Atbash Cipher

Create an implementation of the atbash cipher, an ancient encryption system created in the Middle East.
The Atbash cipher is a simple substitution cipher that relies on transposing all the letters in the alphabet such that the resulting alphabet is backwards. The first letter is replaced with the last letter, the second with the second-last, and so on.
An Atbash cipher for the Latin alphabet would be as follows:
Plain: abcdefghijklmnopqrstuvwxyz
Cipher: zyxwvutsrqponmlkjihgfedcba

First let's take a look on excellent solution from Bob.

Bob's solution

Link to solution in Exercism:

export function encode(plainText: string, isDecoding:boolean = false): string {
  let output: number[] = [];
  let count = 0;
  const aAscii = 'a'.charCodeAt(0);
  const zAscii = 'z'.charCodeAt(0);
  let cAscii: number;

  for (let c of [...plainText.toLowerCase()]){
    if (c >= 'a' && c <= 'z')
      cAscii = zAscii - (c.charCodeAt(0) - aAscii);
    else if (c >= '0' && c <= '9')
      cAscii = c.charCodeAt(0);
    else
      continue;
    if (count == 5) {
      if (!isDecoding) output.push(32);
      count = 0;
    }
    output.push(cAscii);
    count ++;
  }
  return String.fromCharCode.apply(null, output);
}
export function decode(cipherText: string): string {
  return encode(cipherText, true);
}
Enter fullscreen mode Exit fullscreen mode

Pros

The code is well structured.

Cons

  • The method encode includes an additional flag as a parameter which looks redundant and make logic more complex.
  • All logic at one place. The method can be easily splitted into few smaller.
  • Some values can be presented as consts to remove "magic" chars and numbers from the code.
  • we can make function more functional by replacing lets with consts and providing chaining for greater readability.
  • Let's introduce Reg Exps to remove redundant logic!

Possible refactoring

As we can see - the list of possible changes quite big. But the question is - will it help to the end user? Let's take a look!

After some changes

After all mentioned above things applied - the new code is looking like that:

const PUNCTUATION_AND_SPACE_REGEX = /[\s,.!?]/g;
const GROUP_OF_FIVE_REGEX = /(.{1,5})/g;
const A_CODE = 'a'.charCodeAt(0);
const Z_CODE = 'z'.charCodeAt(0);

const groupText = (text: string) => (text.match(GROUP_OF_FIVE_REGEX) ?? []).join(" ");

const isAlphabeticChar = (code: number) => code >= A_CODE && code <= Z_CODE;

const encodeChar = (char: string) => {
  const charCode = char.charCodeAt(0);
  const newCharCode = isAlphabeticChar(charCode) ? A_CODE + (Z_CODE - charCode) : charCode;
  return String.fromCharCode(newCharCode);
}

const cleanText = (text: string) => text
  .toLowerCase()
  .replaceAll(PUNCTUATION_AND_SPACE_REGEX, "");

const applyCipher = (text: string) => [...cleanText(text)]
  .map(encodeChar)
  .join("")

const encode = (plainText: string): string => groupText(applyCipher(plainText));
const decode = (cipherText: string): string => applyCipher(cipherText);
Enter fullscreen mode Exit fullscreen mode

Please, put in comments what solution you prefer more. Also do not hesitate to left links in Exercism for your own solutions - sharing is caring ;)

Possible improvement: encapsulate logic inside class. Waitting for your links to solutions in the comments!

Meanwhile you can take a look on the task where I did some useful things regarding TS types.

Top comments (0)