Где моя реализация rot13 в JavaScript идет неправильно? - PullRequest
24 голосов
/ 06 марта 2009

Код с подсветкой синтаксиса здесь: через Friendpaste

rot13.js:

ОШИБОЧНАЯ

<script>
String.prototype.rot13 = rot13 = function(s)
 {
    return (s = (s) ? s : this).split('').map(function(_)
     {
        if (!_.match(/[A-Za-z]/)) return _;
        c = Math.floor(_.charCodeAt(0) / 97);
        k = (_.toLowerCase().charCodeAt(0) - 96) % 26 + 13;
        return String.fromCharCode(k + ((c == 0) ? 64 : 96));
     }).join('');
 };
</script>

Как вы можете видеть, используя буквально одну строку для присоединения метода к объекту String в виде прототипа, у меня есть метод map (), который я ранее настроил (я точно знаю, что этот код работает отлично ; он просто перебирает каждый элемент в массиве и применяет функцию, указанную в параметре), перебирает каждый символ в строке и делает то, что мне показалось правильным расчетом, чтобы преобразовать строку в ее аналог rot13. Я был грустно ошибался. Кто-нибудь может определить, где я ошибся?

Ответы [ 17 ]

72 голосов
/ 06 марта 2009

Вы можете использовать супер-короткие:

s.replace(/[a-zA-Z]/g,function(c){return String.fromCharCode((c<="Z"?90:122)>=(c=c.charCodeAt(0)+13)?c:c-26);});
16 голосов
/ 01 апреля 2013

Это дает правильные результаты.

function rot13(s)
 {
    return (s ? s : this).split('').map(function(_)
     {
        if (!_.match(/[A-Za-z]/)) return _;
        c = Math.floor(_.charCodeAt(0) / 97);
        k = (_.toLowerCase().charCodeAt(0) - 83) % 26 || 26;
        return String.fromCharCode(k + ((c == 0) ? 64 : 96));
     }).join('');
 }
 
 alert(rot13(rot13("Mark this as accepted answer :)")));
15 голосов
/ 13 февраля 2015

Вот решение с использованием функций replace, indexOf и charAt:

function rot13(s) {
  return s.replace(/[A-Za-z]/g, function (c) {
    return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".charAt(
           "NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm".indexOf(c)
    );
  } );
}

Несмотря на то, что другие ответы «короче» (т. Е. Меньше символов), я думаю, что этот ответ легче понять.

11 голосов
/ 28 января 2013

Просто потому, что он еще короче и понятнее / логичнее:

function rot13(s) {
  return s.replace( /[A-Za-z]/g , function(c) {
    return String.fromCharCode( c.charCodeAt(0) + ( c.toUpperCase() <= "M" ? 13 : -13 ) );
  } );
}
9 голосов
/ 27 апреля 2014

Решение Кевина М компактно и элегантно. Однако есть одна маленькая ошибка: регулярное выражение, используемое с функцией замены, не ограничивает замену буквенными символами. Диапазон символов [A-z] включает знаки пунктуации ([\] ^ _ `), которые будут заменены на буквы, когда их следует оставить в одиночку.

Исправленная версия выглядит так:

function r(a,b){return++b?String.fromCharCode((a<"["?91:123)>(a=a.charCodeAt()+13)?a:a-26):a.replace(/[a-zA-Z]/g,r)}

Это все еще только 116 байтов. Замечательно маленький и довольно умный.

(Извините за публикацию полного ответа; мне все еще не хватает 50 представителей, необходимых для публикации этого комментария к превосходному ответу Кевина.)

5 голосов
/ 13 марта 2014

Вот версия с 80 столбцами, не обновляемая string.prototype, с хорошим отступом и достаточно короткая.

function rot13(str) {
  return str.replace(/[a-zA-Z]/g, function(chr) {
    var start = chr <= 'Z' ? 65 : 97;
    return String.fromCharCode(start + (chr.charCodeAt(0) - start + 13) % 26);
  });
}

И пример, показывающий, что он работает:

rot13('[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]')
"[nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM]"
rot13(rot13('[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]'))
"[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]"
5 голосов
/ 06 марта 2009
var rot13 = String.prototype.rot13 = function(s)
{
  return (s = (s) ? s : this).split('').map(function(_)
  {
    if (!_.match(/[A-Za-z]/)) return _;
    c = _.charCodeAt(0)>=96;
    k = (_.toLowerCase().charCodeAt(0) - 96 + 12) % 26 + 1;
    return String.fromCharCode(k + (c ? 96 : 64));
  }
  ).join('');
};

alert('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.rot13());
yields nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM

Смешивание нулевых и единичных индексов для проигрыша. Я обвиняю Netscape.

4 голосов
/ 05 января 2014

Однострочник весом 116 байт:

function r(a,b){return++b?String.fromCharCode((a<"["?91:123)>(a=a.charCodeAt()+13)?a:a-26):a.replace(/[a-zA-Z]/g,r)}

Использование:

r('The Quick Brown Fox Jumps Over The Lazy Dog.');

3 голосов
/ 06 марта 2009

должен ли% 26 идти после + 13?

k = ((_.toLowerCase().charCodeAt(0) - 96) + 13) % 26;
2 голосов
/ 03 января 2017

Моя версия для гольфа имеет длину 82 байта (по сравнению с Беном Альбертом, который на 35% тяжелее, но мой вдохновенный):

S.replace(/[a-z]/gi,c=>String.fromCharCode((c=c.charCodeAt())+((c&95)>77?-13:13)))

Отличия:

  • без учета регистра, чтобы поймать только английский алфавит.
  • Функции стрелок без возврата и фигурных скобок.
  • удалить параметры из charCodeAt. * ​​1013 *
  • проверка кода, указанного в строке.
  • делает + 13-26 = -13.
  • тест в верхнем регистре (&95) против 77 (78 + 13 = 91, переполнение).

Дополнительно: если вы хотите выполнить ROT5 для цифр, добавьте: .replace(/\d/gi,c=>(c>4?-5:5)+c*1)

...