JavaScript-решение для шифрования ROT13

первоначально опубликовано на hellodevworld.com

Добро пожаловать в третий день из 365 дней программирования! Сегодня мы собираемся погрузиться в шифры. В частности, шифр Цезаря ROT13.

Отказ от ответственности: есть МНОГИЕ способы решить эту проблему, это несколько ответов, которые я увижу или использую на собеседовании по программированию и приму как правильные ответы.

TLDR: объяснение наилучшего решения в нижней части сообщения и фактические решения в нижней части каждого раздела.

Что такое шифр Цезаря ROT13?

Если вы когда-либо проводили какие-либо исследования в области кибербезопасности или криптографии, вы, вероятно, слышали о шифре Цезаря. Если нет, шифр Цезаря — это шифр сдвига, который сдвигает все буквы алфавита на заданное количество букв вниз по алфавиту. ROT3 является наиболее распространенным шифром Цезаря. ROT13 означает, что каждая буква заменена 13-й буквой после нее в алфавите.

Проблема

Создайте функцию, которая принимает строку и возвращает строку, в которой каждая буква заменена 13-й буквой после нее в алфавите (ROT13). Если в строку включены числа или специальные символы, они должны быть возвращены как есть.

Примеры:

rot13("Hello Dev World is awesome!")   // Uryyb Qri Jbeyq vf njrfbzr
    rot13("my dogs are the cutest dogs in the world")   // zl qbtf ner gur phgrfg qbtf va gur jbeyq
    rot13("abcdefghijklmnopqrstuvwxyz")  // nopqrstuvwxyzabcdefghijklm
    rot13("#365DaysOfCoding") // #365QnlfBsPbqvat

Решения

Я запускал все решения в jsbench, и каждый раз они были в пределах пары процентных пунктов. Было непоследовательно, кто из них был самым быстрым. Это говорит нам о том, что между различными решениями нет существенной разницы в производительности.

Итак, давайте разберем, что нам нужно сделать

  • возможность 1
  • есть строка алфавита
  • иметь зашифрованную строку алфавита
  • сделать замену на основе индексов
  • возможность 2
  • иметь строку алфавита
  • заменить на индекс буквы + 13
  • возможность 3
  • заменить сообщение на
  • получить код UTF для буквы
  • добавьте 13 или вычтите 13 из этого кода (добавьте, если перед m вычтите после m)
  • получить строку на основе этого кода

Решение 1

Сначала нам нужно создать функцию, которая принимает сообщение

const rot13 = (message) => {
    // have a string of the alphabet
    // have a string of the alphabet ciphered
    // do a replace based of of indexes
}

Теперь нам нужно установить известный нам алфавит в переменную. Я использовал const здесь, потому что он не изменится.

const rot13 = (message) => {
  const originalAlpha = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
    // have a string of the alphabet ciphered
    // do a replace based of of indexes
}

Мы собираемся сделать то же самое снова, но с зашифрованной версией алфавита.

const rot13 = (message) => {
    const originalAlpha = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
    const cipher = "nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM"
    // do a replace based of of indexes
}

И, наконец, мы будем использовать .replace (), чтобы заменить букву из сообщения буквой из шифра, вытащив индекс буквы, на которой мы находимся, из исходного алфавита и используя этот индекс, чтобы вытащить букву из того же алфавита. индекс в зашифрованной строке. .replace() будет добавлен к сообщению, так что оно будет делать это для каждой буквы в переданной строке. Поскольку регулярное выражение проверяет только буквы, все числа, пробелы и знаки препинания останутся прежними.

const rot13 = (message) => {
  const originalAlpha = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
  const cipher = "nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM"
  return message.replace(/[a-z]/gi, letter => cipher[originalAlpha.indexOf(letter)])
}

Решение 2

Для этого решения мы собираемся снова создать функцию и добавить алфавит в переменную.

const rot13 = (message) => {
  const alpha = 'abcdefghijklmnopqrstuvwxyzabcdefghijklmABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLM';
  //replace with index of the letter + 13
}

На этот раз замена не потянет

const rot13 = (message) => {
  const alpha = 'abcdefghijklmnopqrstuvwxyzabcdefghijklmABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLM';
  return message.replace(/[a-z]/gi, letter => alpha[alpha.indexOf(letter) + 13]);
}

Вместо того, чтобы добавлять переменную для зашифрованного алфавита, мы можем просто выполнить эту математику при замене.

Решение 3

Еще одно умное решение, которое я видел раньше, — это последнее решение. Это умное решение, состоящее из 1 строки, но оно использует встроенные функции, которые не являются общими, что может привести к проблемам с читабельностью.

function rot13(message) {
    return message.replace(/[a-z]/gi, letter => String.fromCharCode(letter.charCodeAt(0) + (letter.toLowerCase() <= 'm' ? 13 : -13)));
}

Поскольку это 1 лайнер, я просто попытаюсь объяснить, что он делает, а не разбивать его. fromCharCode возвращает строку из кода UTF-16. Таким образом, каждое число от 0 до 65535 привязано к строке. charCodeAt возвращает код UTF-16, который мы декодируем с помощью fromCharCode. 0, который передается fromCharCode, является индексом, и, поскольку мы передаем только 1 букву, индекс всегда будет 0. Мы делаем + 13, если он ниже m, потому что это приведет нас до x, а затем, как только мы достигнем m, мы в середине, и это отображается на x, поэтому нам нужно начать алфавит, а это означает, что нам нужно получить код для букв в начале алфавита, поэтому нам нужно идти назад, а не вперед. Мы выполняем замену регулярного выражения, поэтому буквы заменяются этой возвращаемой буквой.

Вывод

Производительность для всех трех решений незначительна. Последнее решение умное, но не самое простое для понимания. Два других очень похожи, но опять же есть много способов написать решение для этого.

Пожалуйста, оставьте свои решения, которые вы придумали, в разделе комментариев. Если у вас есть какая-либо задача, которую вы хотели бы решить, также оставьте ее в комментариях ниже, вы можете увидеть, как она появится! Если вы хотите, чтобы задача каждый день утром приходила вам на почту и уведомление, когда решение опубликовано, подпишитесь здесь!