¿Dónde va mal mi implementación de rot13 en JavaScript?

Código en cuestión con resaltado de syntax aquí: a través de Friendpaste

rot13.js:

ERRÓNEO

 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(''); };  

Como puede ver, usando literalmente una sola línea para adjuntar un método al objeto String a la prototyping, tengo un método map () que configuré previamente (estoy seguro de que ese código funciona perfectamente; es simplemente iterando sobre cada elemento de la matriz y aplicando la función especificada en el parámetro) recorra cada carácter en una cadena y haga lo que pensé que eran los cálculos adecuados para transformar la cadena en su equivalente rot13’d. Estaba tristemente equivocado. ¿Alguien puede detectar dónde me equivoqué?

    17 Solutions collect form web for “¿Dónde va mal mi implementación de rot13 en JavaScript?”

    Podrías usar el super corto:

     s.replace(/[a-zA-Z]/g,function(c){return String.fromCharCode((c< ="Z"?90:122)>=(c=c.charCodeAt(0)+13)?c:c-26);}); 

    Esto da resultados correctos.

     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 :)"))); 

    Aquí hay una solución que utiliza las funciones replace , indexOf y charAt :

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

    A pesar de que otras respuestas son “más cortas” (es decir, un número menor de caracteres), creo que esta respuesta es más fácil de entender.

    Solo porque es aún más corto y también más comprensible / lógico:

     function rot13(s) { return s.replace( /[A-Za-z]/g , function(c) { return String.fromCharCode( c.charCodeAt(0) + ( c.toUpperCase() < = "M" ? 13 : -13 ) ); } ); } 

    La solución de Kevin M es compacta y elegante. Sin embargo, tiene un pequeño error: la expresión regular utilizada con la función de reemplazo no limita la sustitución a los caracteres alfabéticos. El rango de caracteres [Az] incluye caracteres de puntuación ( [ \ ] ^ _ ` ), que se intercambiarán por letras cuando se deben dejar solo.

    La versión fija se ve así:

     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)} 

    Todavía es sólo 116 bytes. Notablemente pequeño y bastante inteligente.

    (Perdón por la publicación de la respuesta completa; todavía me faltan los 50 representantes necesarios para publicar esto como un comentario a la excelente respuesta de Kevin).

     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 

    Mezcla de índices basados ​​en cero y basados ​​en uno para perder. Culpo a Netscape.

    Aquí hay una versión que tiene 80 columnas, no actualiza string.prototype, está bien sangrada y es razonablemente corta.

     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); }); } 

    Y un ejemplo que muestra que está funcionando:

     rot13('[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]') "[nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM]" rot13(rot13('[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]')) "[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]" 

    Una sola línea que pesa 116 bytes:

     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)} 

    Uso:

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

    ¿El% 26 debería venir después del + 13?

     k = ((_.toLowerCase().charCodeAt(0) - 96) + 13) % 26; 

    Todavía hay espacio para la mejora, la verificación (c < = "Z") es en realidad una verificación contra el punto de código (que necesitamos más adelante), ¡seguir esa idea nos da una victoria!

    // contra el estilo de Kevin M: 115 caracteres (vs 116)
    // 102 caracteres con búfer nodejs (ver más abajo)

     function r(a,b){return++b?String.fromCharCode(((a=a.charCodeAt())<91?78:110)>a?a+13:a-13):a.replace(/[a-zA-Z]/g,r)} //nodejs style function r(a,b){return++b?Buffer([((a=Buffer(a)[0])<91?78:110)>a?a+13:a-13]):a.replace(/[a-zA-Z]/g,r)} 

    // versus el estilo de Ben Alpert: 107 caracteres (vs 112)
    // 93 caracteres con búfer nodejs (ver más abajo)

     s.replace(/[a-zA-Z]/g,function(a){return String.fromCharCode(((a=a.charCodeAt())<91?78:110)>a?a+13:a-13)}); //nodejs style s.replace(/[a-zA-Z]/g,function(a){return Buffer([((a=Buffer(a)[0])<91?78:110)>a?a+13:a-13])}) 

    // Mismo código, formateado para producción.

     String.prototype.rot13 = function() { return this.replace(/[a-zA-Z]/g, function(a){ return String.fromCharCode(((a=a.charCodeAt())<91?78:110)>a?a+13:a-13); }); } 

    En nodejs, puede usar Buffer para convertir / serializar puntos de código, por ejemplo:

     var a=65; ""+Buffer([a]) == "A" // note that the cast is done automatically if needed String.fromCharCode(a) == "A" var b="A"; Buffer(a)[0] == 65 a.charCodeAt() == 65 

    Mi versión de golf tiene una longitud de 82 bytes (en comparación con Ben Albert, que es un 35% más pesado, pero inspiró la mía):

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

    Diferencias

    • Insensible a las mayúsculas y minúsculas para capturar solo el alfabeto inglés
    • Funciones de flecha sin retorno y tirantes.
    • eliminar parámetros de charCodeAt.
    • prueba contra el código instalado de cadena.
    • haciendo + 13-26 = -13.
    • prueba en mayúsculas ( &95 ) contra 77 (78 + 13 = 91, desbordamiento).

    Extra: si desea realizar ROT5 en dígitos, agregue: .replace(/\d/gi,c=>(c>4?-5:5)+c*1)

    Combinando varias técnicas aquí, se me ocurrió esta función JavaScript ES6 de 78 caracteres, que funciona en Nodo:

     rot13=s=>s.replace(/[az]/ig,c=>Buffer([((d=Buffer(c)[0])&95)<78?d+13:d-13])); 

    Aquí hay una biblioteca de JavaScript que realiza la sustitución de letras ROT-n: https://github.com/mathiasbynens/rot

    rot es una biblioteca de JavaScript que realiza la sustitución rotatoria de letras. Se puede usar para cambiar cualquier letra ASCII en la cadena de entrada por un número dado de posiciones en el alfabeto. Para ROT-13 la cadena 'abc' , por ejemplo:

     // ROT-13 is the default rot('abc'); // → 'nop' // Or, specify `13` explicitly: rot('abc', 13); // → 'nop' 

    Esto no significa en modo alguno intentar competir con las excelentes cosas aquí, como pueden ver. No puedo hacer comentarios, pero tengo mi propio bash de principiante para escribir esto en JS y hacerlo funcionar antes de leer soluciones más elegantes aquí. Voy a compartirlo aquí.

    Intenté escribirlo con indexOf , un indexOf , agregando 13, mediante String.fromCharCode() y CharCodeAt() . Se estaban alargando demasiado, la función de ayuda en este caso es innecesaria, pero esta fue la más corta:)

     function rot13(string) { var result = '', store, str = string.toLowerCase(); //helper function function strgBreak(a){ var result = []; return result = a.split(''); } //rot13 arrays var alphArr = strgBreak('abcdefghijklmnopqrstuvwxyz'); var inverseArr = strgBreak('nopqrstuvwxyzabcdefghijklm'); for ( var i = 0; i < str.length; i++ ) { if (alphArr.indexOf( str[i] ) !== -1) { result += inverseArr[ alphArr.indexOf( str[i] ) ]; } else result += str[i]; } return result.toUpperCase(); } 

    Aquí hay un enfoque moderno para el cifrado de sustitución ROT13:

     const ROT13 = s => s.replace(/[az]/gi, c => String.fromCharCode(c.charCodeAt() + 13 - 26 * /[nz]/i.test(c))); console.log(ROT13('The quick brown fox jumps over 13 lazy dogs.')); 

    Si bien realmente me gusta la solución RegEx, principalmente emprendí el proyecto para ver si podía hacerlo. Me alegra informar que finalmente logré hacerlo:

     String.prototype.rot13 = rot13 = function(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(''); } 

    Versión de CoffeeScript de la respuesta de @ ben-alpert:

     string.replace /[a-zA-Z]/g, (c) -> String.fromCharCode if (if c < = 'Z' then 90 else 122) >= (c = c.charCodeAt(0) + 13) then c else c - 26 

    O como función:

     ROT13 = (string) -> string.replace /[a-zA-Z]/g, (c) -> String.fromCharCode if (if c < = 'Z' then 90 else 122) >= (c = c.charCodeAt(0) + 13) then c else c - 26 ROT13('asd') # Returns: 'nfq' 
    Javascript tiene muchos buenos JS marco (como Node.js AngularJS Vue.js React.js) es el mejor lenguaje de script.