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 sh
Here is a function that receives text orig dest and replaces in text each character for the one in the corresponding position in dest.
Is is not good enough for cases where more than one character must be replaced by only one or vice-versa. It is not good enough for removing accents from Portuguese texts, which is my use case.
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 );
}
How to use it:
var port = "ÀÂÃÁÉÊÍÓÔÕÜÚÇáàãâêéíóõôúüç";
var ascii = "AAAAEEIOOOUUCaaaaeeiooouuc";
console.log(tr("não têm ações em seqüência", port, ascii)) ;
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('');
I wanted a function that allows passing a custom map object, so I wrote one based on Jonathan Lonowski's answer. If you are trying to replace special characters (the kind that need to be escaped in regular expressions) you'll have to do some more work.
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]);
};
And it's used like this:
const map = { a: 'A', b: 'B', d: 'D' };
mapReplace('abcde_edcba', map);
// ABcDe_eDcBA
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.)
Similiar to Jonathan Lonowski answer but with words support, not just single tr chars
"aaabbccddeeDDDffd".replace( /(a|cc|DDD|dd)/g, m => ({'a':'B', 'cc':'DDD', 'DDD':'ZZZ', dd:'QQ'}[m]) )
// RESULT: "BBBbbDDDQQeeZZZffd"
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 ].