Единозначный парный шифр на js

В единозначном шифре каждому знаку ключа соответствует одна определенная буква. В связи с тем, что ключ должен быть легким для запоминания, чистая форма единозначного шифра совершенно не употребительна. Зато в большом ходу его упрощенная модуляция – парный единозначный шифр. Представим себе фразу из 17 различных букв, т.е. половины азбуки. Оставшиеся 17 букв подпишем под этой фразой в алфавитном порядке. Например, ключ: введите сюда описание изображения

Каждая верхняя буква с лежащей под ней нижней составляет пару, в которой одна буква взаимозамещает другую. Хочу попросить совета. Каким способом лучше осуществить данный шифр на JS? Использовать объекты (ключ - значение), двумерные массивы с парами букв или может есть иные советы по данному поводу? Буду благодарен любому ответу. Так же был бы рад некоему алгоритму решения.


Ответы (2 шт):

Автор решения: Mark Minerov

Для такого лучше использовать объекты:

const crypt = {
    'a': 'b',
    'Q': 'S'
    ....
}

Затем можно обращаться как к Object.values(), так и к Object.entries(), что упростит решение данной задачи.

→ Ссылка
Автор решения: Leonid

Во всех вариантах используется возможность передать в метод replace вторым параметром функцию, управляющую этими заменами. Она может принимать четыре параметра. Здесь принимается один - m - match - совпадающий символ. Функция должна возвращать подстроку для замены совпадающего символа. Подстрока берется из объекта secret по key == m или по соответствию двух массивов через индекс.

Подробнее: https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/String/replace#Specifying_a_function_as_a_parameter

Как вариант:

// Получаем полноценные массивы из строк, составляющих алфавит и ряда символов, соответствующих каждой букве этого алфавита
// Для простоты сместил секретные символы на один и все, но можно как угодно
let alphabet = [...'АБВГДЕЁЖЗИЙКЛМНОПРСУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзийклмнопрстуфхцчшщъыьэюя'];
let shifr = [...'БВГДЕЁЖЗИЙКЛМНОПРСУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзийклмнопрстуфхцчшщъыьэюяA'];

let secret = {}; // Объявляем объект, где будем хранить соответствия

// Наполняем объект secret парами ключ: значение (можно и `reduce` использовать, но я с ним не дружу))))    
alphabet.forEach((a,i) => {
  secret[a] = shifr[i];
})



str = 'Железный шприц дома'; // Строка для обработки
// Функция для передачи в качестве второго параметра `String.prototype.replace()`
function howTo(m){
	return secret[m];  // Возвращает значение ключа `m` в объекте `secret`
}
// Ищем все буквы русского алфавита и вызываем функцию `howTo` для каждого случая (флаг `g`)
str = str.replace(/[а-яёА-ЯЁ]/g, howTo); 

console.log(str);

Сокращенный вариант(кроме подготовки secret):

let alphabet = [...'АБВГДЕЁЖЗИЙКЛМНОПРСУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзийклмнопрстуфхцчшщъыьэюя'];
let shifr = [...'БВГДЕЁЖЗИЙКЛМНОПРСУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзийклмнопрстуфхцчшщъыьэюяA'];

let secret = {};

alphabet.forEach((a,i) => {
  secret[a] = shifr[i];
})


str = 'Железный шприц дома'.replace(/[а-яёА-ЯЁ]/g, m => secret[m]);

console.log(str);

Можно и не формируя объект:

let alphabet = [...'АБВГДЕЁЖЗИЙКЛМНОПРСУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзийклмнопрстуфхцчшщъыьэюя'];
let shifr = [...'БВГДЕЁЖЗИЙКЛМНОПРСУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзийклмнопрстуфхцчшщъыьэюяA'];

str = 'Железный шприц дома'.replace(/[а-яёА-ЯЁ]/g, m => shifr[alphabet.indexOf(m)]);

console.log(str);

Если вопрос с ключом вызывает сложности:

let kluch = 'желёзныйшпицъдома';

function encrypt(kluch, str){

  let alphabet = [...'абвгдеёжзиiклмнопрстуфхцчшщъыьэюя'].filter(s => !kluch.includes(s));
  
  let key = [...kluch, ...alphabet];
  let anti = [...alphabet, ...kluch];
  
  str = str.replace(/[а-яё]/gi, m => anti[key.indexOf(m.toLowerCase())]);
  
  return str;  
}



console.log(encrypt(kluch, 'Не знаю, получится разглядеть?'));
console.log(encrypt(kluch, encrypt(kluch, 'Не знаю, получится разглядеть?'))); // Может так?..
console.log(encrypt(kluch, 'Если: железный шпицъ дома'));

→ Ссылка