Où est-ce que mon implémentation en une seule ligne de rot13 en JavaScript va mal?

Code en question avec la syntaxe surlignée ici:par 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>

comme vous pouvez le voir, en utilisant littéralement une seule ligne pour attacher une méthode à L'objet String a la prototyping, j'ai une méthode map() que j'ai déjà mise en place (je sais avec certitude que ce code fonctionne parfaitement; c'est simplement itérer sur chaque élément du tableau et appliquer la fonction spécifiée dans le paramètre) passer sur chaque caractère dans une chaîne et faire ce que je pensais être les bons calculs pour transformer la chaîne en son pendant rot13. J'ai été malheureusement erronée. Quelqu'un peut-il endroit où je suis allé mal?

22
demandé sur Stefano Borini 2009-03-06 06:58:19

16 réponses

Vous pouvez utiliser le super-court:

s.replace(/[a-zA-Z]/g,function(c){return String.fromCharCode((c<="Z"?90:122)>=(c=c.charCodeAt(0)+13)?c:c-26);});
69
répondu Sophie Alpert 2009-03-06 04:32:26

Cela donne des résultats corrects.

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('');
 }
14
répondu Zibri 2015-07-03 09:20:00

Voici une solution en utilisant replace,indexOf et charAt fonctions:

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

bien que d'autres réponses soient "plus courtes" (c.-à-d. moins de caractères), je pense que cette réponse est plus facile à comprendre.

11
répondu Stephen Quan 2017-03-30 05:48:00

la solution de Kevin M est compacte et élégante. Il a une petite erreur: l'expression régulière utilisée avec la fonction replace ne limite pas la substitution de caractères alphabétiques. [A-z] la plage de caractères comprend les caractères de ponctuation ([\] ^ _ `), qui seront échangées contre des lettres alors qu'elles devraient être laissées seules.

la version corrigée ressemble à ceci:

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

il ne reste que 116 octets. Remarquablement petit et tout à fait intelligent.

(Désolé pour la réponse complète de la mutation; je suis toujours en manque de la de 50 répétitions nécessaires à la poste comme un commentaire de Kevin excellente réponse.)

9
répondu Lonnon Foster 2014-04-26 22:05:11

Juste parce que c'est encore plus court et plus compréhensible/logique:

function rot13(s) {
  return s.replace( /[A-Za-z]/g , function(c) {
    return String.fromCharCode( c.charCodeAt(0) + ( c.toUpperCase() <= "M" ? 13 : -13 ) );
  } );
}
8
répondu Herman 2014-04-27 09:53:13
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

Mélange de base zéro et les indices pour le perdre. Je blâme Netscape.

5
répondu Sparr 2013-08-23 19:47:15

Voici une version de 80 colonnes, qui ne met pas à jour la chaîne de caractères.prototype, bien dentelé et assez court.

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

Et un exemple montrant qu'il est de travail:

rot13('[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]')
"[nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM]"
rot13(rot13('[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]'))
"[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]"
4
répondu Vjeux 2014-03-13 01:07:13

One-liner qui pèse 116 octets:

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

Utilisation:

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

4
répondu Kevin M 2014-09-04 18:57:27

le % 26 devrait-il venir après le + 13?

k = ((_.toLowerCase().charCodeAt(0) - 96) + 13) % 26;
3
répondu cobbal 2009-03-06 04:11:33

il y a encore de la place pour l'amélioration, la vérification (c< = "Z") est en fait une vérification par rapport au codepoint (que nous aurons besoin plus tard), suite à cette idée nous donne une victoire !

//versus Kevin M style : 115 caractères (vs 116)

// 102 caractères Avec tampon nodejs (voir ci-dessous)

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 Ben Alpert style: 107 chars (vs 112)

// 93 caractères Avec tampon nodejs (voir ci-dessous)

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

/ même code, formaté pour la production

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

dans nodejs, vous pouvez utiliser Buffer pour lancer/sérialiser les codépoints, par exemple:

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
2
répondu 131 2015-01-31 22:24:54

Mon ont joué au golf version est de 82 octets de long (contre Ben Albert, qui est 35% plus lourd, mais qui l'a inspiré le mien):

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

Différences:

  • casse à attraper alphabet anglais.
  • fonctions flèche sans retour et Attelles.
  • supprimer les paramètres de charCodeAt.
  • test contre code insté de chaîne.
  • faire + 13-26=-13.
  • test en majuscules (&95) contre 77 (78+13=91, débordement).

Extra: si vous voulez effectuer ROT5 sur les chiffres, ajouter: .replace(/\d/gi,c=>(c>4?-5:5)+c*1)

2
répondu ESL 2017-01-03 06:07:43

en combinant différentes techniques ici, j'ai créé cette fonction ES6 JavaScript de 78 caractères, qui fonctionne sur Node:

rot13=s=>s.replace(/[a-z]/ig,c=>Buffer([((d=Buffer(c)[0])&95)<78?d+13:d-13]));
2
répondu DSchnellDavis 2017-01-13 05:28:57
https://github.com/mathiasbynens/rot

rot est une bibliothèque JavaScript qui effectue la substitution de lettres par rotation. Il peut être utilisé pour déplacer n'importe quelles lettres ASCII dans la chaîne de caractères d'entrée par un nombre donné de positions dans l'alphabet. À ROT-13, la chaîne 'abc' par exemple:

// ROT-13 is the default
rot('abc');
// → 'nop'

// Or, specify `13` explicitly:
rot('abc', 13);
// → 'nop'
1
répondu Mathias Bynens 2014-06-16 10:39:18

ce n'est en aucun cas essayer de rivaliser avec l'excellent truc ici, comme vous voyez, je ne peux pas commenter, mais j'ai ma propre tentative novice d'écrire ceci dans JS et de le faire fonctionner avant que je lise des solutions plus élégantes ici - je vais le partager ici.

j'ai essayé de l'écrire avec indexOf, un switch, en ajoutant 13, par String.fromCharCode() et CharCodeAt(). Ils ont été trop longtemps - la fonction d'assistance de celui-ci est inutile, mais c'était mon plus court : )

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(); 
}
1
répondu isosceles 2016-05-26 00:12:29

Tandis Que I vraiment comme la solution RegEx, j'ai principalement entrepris le projet pour voir si je pouvais le faire. Heureux d'annoncer que j'ai enfin réussit à le faire:

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('');
 }
0
répondu Hexagon Theory 2009-03-06 16:06:37

version CoffeeScript de @ben-alpert 's réponse:

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

Ou comme fonction:

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'
0
répondu dr.dimitru 2017-05-23 12:32:35