J'ai essayé de comprendre comment mapper un ensemble de caractères dans une chaîne à un autre ensemble similaire à la fonction tr
en Perl.
J'ai trouvé ce site qui montre des fonctions équivalentes en JS et Perl , mais malheureusement pas d'équivalent tr.
la fonction tr
(translittération) en Perl mappe les caractères un à un, donc
data =~ tr|\-_|+/|;
mapperait
- => + and _ => /
Comment cela peut-il être fait efficacement en JavaScript?
Il n'y a pas d'équivalent intégré, mais vous pouvez vous en approcher avec replace
:
data = data.replace(/[\-_]/g, function (m) {
return {
'-': '+',
'_': '/'
}[m];
});
Je ne peux pas garantir "efficace", mais cela utilise une expression régulière et un rappel pour fournir le caractère de remplacement.
function tr( text, search, replace ) {
// Make the search string a regex.
var regex = RegExp( '[' + search + ']', 'g' );
var t = text.replace( regex,
function( chr ) {
// Get the position of the found character in the search string.
var ind = search.indexOf( chr );
// Get the corresponding character from the replace string.
var r = replace.charAt( ind );
return r;
} );
return t;
}
Pour les longues chaînes de caractères de recherche et de remplacement, il peut être utile de les mettre dans un hachage et de renvoyer la fonction à partir de cela. c'est-à-dire que tr/abcd/QRST/devient le hachage {a: Q, b: R, c: S, d: T} et le rappel renvoie le hachage [chr].
Méthode:
String.prototype.mapReplace = function(map) {
var regex = [];
for(var key in map)
regex.Push(key.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"));
return this.replace(new RegExp(regex.join('|'),"g"),function(Word){
return map[Word];
});
};
Un parfait exemple:
var s = "I think Peak rocks!"
s.mapReplace({"I think":"Actually","rocks":"sucks"})
// console: "Actually Peak sucks!"
Cela mappera tous les a
s à b
et tous les y
à z
var map = { a: 'b', y: 'z' };
var str = 'ayayay';
for (var i = 0; i < str.length; i++)
str[i] = map[str[i]] || str[i];
ÉDITER:
Apparemment, vous ne pouvez pas faire ça avec des cordes. Voici une alternative:
var map = { a: 'b', y: 'z' };
var str = 'ayayay', str2 = [];
for (var i = 0; i < str.length; i++)
str2.Push( map[str[i]] || str[i] );
str2.join('');
Ces fonctions, qui sont similaires à la façon dont il est construit en Perl.
function s(a, b){ $_ = $_.replace(a, b); }
function tr(a, b){ [...a].map((c, i) => s(new RegExp(c, "g"), b[i])); }
$_ = "Εμπεδοκλης ο Ακραγαντινος";
tr("ΑΒΓΔΕΖΗΘΙΚΛΜΝΟΠΡΣΤΥΦΧΩ", "ABGDEZITIKLMNOPRSTIFHO");
tr("αβγδεζηθικλμνοπρστυφχω", "abgdezitiklmnoprstifho");
s(/Ξ/g, "X"); s(/Ψ/g, "Ps");
s(/ξ/g, "x"); s(/ψ/g, "Ps");
s(/ς/g, "s");
console.log($_);
En Perl, on peut aussi écrire
tr{-_}{+/}
comme
my %trans = (
'-' => '+',
'_' => '/',
);
my $class = join '', map quotemeta, keys(%trans);
my $re = qr/[$class]/;
s/($re)/$trans{$1}/g;
Cette dernière version peut sûrement être implémentée dans JS sans trop de problèmes.
(Ma version n'a pas la duplication de la solution de Jonathan Lonowski.)
Voici une fonction qui reçoit le texte d'origine dest et remplace dans le texte chaque caractère pour celui à la position correspondante dans dest.
Cela ne suffit pas pour les cas où plusieurs caractères doivent être remplacés par un seul ou vice versa. Il ne suffit pas de supprimer les accents des textes portugais, ce qui est mon cas d'utilisation.
function tr(text, orig, dest) {
console.assert(orig.length == dest.length);
const a = orig.split('').map(i=> new RegExp(i, 'g'));
const b = dest.split('');
return a.reduce((prev, curr, idx) => prev.replace(a[idx], b[idx]), text );
}
Comment l'utiliser:
var port = "ÀÂÃÁÉÊÍÓÔÕÜÚÇáàãâêéíóõôúüç";
var ascii = "AAAAEEIOOOUUCaaaaeeiooouuc";
console.log(tr("não têm ações em seqüência", port, ascii)) ;
Semblable à la réponse de Jonathan Lonowski mais avec un support de mots, pas seulement des caractères de tr
"aaabbccddeeDDDffd".replace( /(a|cc|DDD|dd)/g, m => ({'a':'B', 'cc':'DDD', 'DDD':'ZZZ', dd:'QQ'}[m]) )
// RESULT: "BBBbbDDDQQeeZZZffd"
Je voulais une fonction qui permette de passer un objet de carte personnalisé, alors j'en ai écrit une basée sur la réponse de Jonathan Lonowski . Si vous essayez de remplacer des caractères spéciaux (le type qui doit être échappé dans les expressions régulières), vous devrez faire un peu plus de travail.
const mapReplace = (str, map) => {
const matchStr = Object.keys(map).join('|');
if (!matchStr) return str;
const regexp = new RegExp(matchStr, 'g');
return str.replace(regexp, match => map[match]);
};
Et c'est utilisé comme ceci:
const map = { a: 'A', b: 'B', d: 'D' };
mapReplace('abcde_edcba', map);
// ABcDe_eDcBA