I've been trying to figure out how to map a set of characters in a string to another set similar to the tr
function in Perl.
I found this site that shows equivalent functions in JS and Perl, but sadly no tr equivalent.
the tr
(transliteration) function in Perl maps characters one to one, so
data =~ tr|\-_|+/|;
would map
- => + and _ => /
How can this be done efficiently in JavaScript?
There isn't a built-in equivalent, but you can get close to one with replace
:
data = data.replace(/[\-_]/g, function (m) {
return {
'-': '+',
'_': '/'
}[m];
});
Method:
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];
});
};
A perfect example:
var s = "I think Peak rocks!"
s.mapReplace({"I think":"Actually","rocks":"sucks"})
// console: "Actually Peak sucks!"
I can't vouch for 'efficient' but this uses a regex and a callback to provide the replacement character.
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;
}
For long strings of search and replacement characters, it might be worth putting them in a hash and have the function return from that. ie, tr/abcd/QRST/ becomes the hash { a: Q, b: R, c: S, d: T } and the callback returns hash[ chr ].
This will map all a
s to b
and all y
to 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];
EDIT:
Apparently you can't do that with strings. Here's an 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('');
This functions, which are similar how it's built in 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($_);
In Perl, one can also write
tr{-_}{+/}
as
my %trans = (
'-' => '+',
'_' => '/',
);
my $class = join '', map quotemeta, keys(%trans);
my $re = qr/[$class]/;
s/($re)/$trans{$1}/g;
This latter version can surely be implemented in JS without much trouble.
(My version lacks the duplication of Jonathan Lonowski's solution.)