net - ¿Dónde va mal la implementación de rot13 en JavaScript de una línea?
javascript ejemplos pdf (17)
¿El% 26 debería venir después del + 13?
k = ((_.toLowerCase().charCodeAt(0) - 96) + 13) % 26;
Código en cuestión con resaltado de sintaxis aquí: a través de 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>
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é?
Aquí hay un enfoque moderno para el cifrado de sustitución ROT13:
const ROT13 = s =>
s.replace(/[a-z]/gi, c =>
String.fromCharCode(c.charCodeAt() + 13 - 26 * /[n-z]/i.test(c)));
console.log(ROT13(''The quick brown fox jumps over 13 lazy dogs.''));
El resultado del caso de prueba anterior es:
Gur dhvpx oebja sbk whzcf bire 13 ynml qbtf.
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. Puede usarse para desplazar 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''
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 de caracteres más bajo), creo que esta respuesta es más fácil de entender.
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 lo muestra está funcionando:
rot13(''[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]'')
"[nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM]"
rot13(rot13(''[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]''))
"[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]"
Combinando varias técnicas aquí, se me ocurrió esta función JavaScript ES6 de 78 caracteres, que funciona en Node:
rot13=s=>s.replace(/[a-z]/ig,c=>Buffer([((d=Buffer(c)[0])&95)<78?d+13:d-13]));
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('''');
}
Esto no significa en modo alguno intentar competir con las excelentes cosas aquí, como puede ver, no puedo hacer comentarios, pero tengo mi propio intento de 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();
}
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 solos.
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 las 50 repeticiones necesarias para publicar esto como un comentario a la excelente respuesta de Kevin).
Mi versión de golf tiene una longitud de 82 bytes (vs. 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
- Insensibilidad de 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)
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);});
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('''');
}
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 ) );
} );
}
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])})
// El mismo código, formateado para la 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
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.'');
Versión de CoffeeScript de la answer 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''
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
Mezclando índices basados en cero y basados en uno para perder. Culpo a Netscape.