你如何映射替换Javascript中的字符类似于Perl中的'tr'函数?

时间:2012-05-23 19:33:53

标签: javascript perl character-encoding transliteration

我一直在试图弄清楚如何将字符串中的一组字符映射到另一个类似于Perl中的tr函数的集合。

我找到this site that shows equivalent functions in JS and Perl,但遗憾的是没有tr等价物。

Perl中的tr(音译)函数将字符一对一映射,所以

     data =~ tr|\-_|+/|;

会映射

     - => + and _ => /

如何在JavaScript中有效地完成这项工作?

9 个答案:

答案 0 :(得分:49)

没有内置的等效内容,但您可以使用replace接近一个:

data = data.replace(/[\-_]/g, function (m) {
    return {
        '-': '+',
        '_': '/'
    }[m];
});

答案 1 :(得分:5)

我不能保证“有效”,但这会使用正则表达式和回调来提供替换字符。

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

对于长字符串的搜索和替换字符,可能值得将它们放在哈希中并使函数从中返回。即,tr / abcd / QRST /成为散列{a:Q,b:R,c:S,d:T},回调返回散列[chr]。

答案 2 :(得分:5)

方法:

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

一个完美的例子:

var s = "I think Peak rocks!"
s.mapReplace({"I think":"Actually","rocks":"sucks"})
// console: "Actually Peak sucks!"

答案 3 :(得分:3)

这会将所有a映射到b,将所有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];

编辑:

显然你不能用字符串做到这一点。这是另一种选择:

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('');

答案 4 :(得分:2)

这个函数与它在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($_);

答案 5 :(得分:1)

在Perl中,还可以编写

tr{-_}{+/}

作为

my %trans = (
   '-' => '+',
   '_' => '/',
);

my $class = join '', map quotemeta, keys(%trans);
my $re = qr/[$class]/;

s/($re)/$trans{$1}/g;

后一版本肯定可以在JS中实现,而不会有太多麻烦。

(我的版本缺少Jonathan Lonowski解决方案的重复。)

答案 6 :(得分:0)

我想要一个允许传递自定义地图对象的函数,因此我根据Jonathan Lonowski的答案写了一个。如果要替换特殊字符(需要在正则表达式中转义的字符),则必须做更多的工作。

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

它的用法如下:

const map = { a: 'A', b: 'B', d: 'D' };
mapReplace('abcde_edcba', map);
// ABcDe_eDcBA

答案 7 :(得分:0)

这是一个接收orig dest文本的函数,并将dest中相应位置的每个字符替换为文本。

对于不能仅用一个字符替换一个以上字符或反之亦然的情况还不够好。从我的用例中删除葡萄牙语中的重音是不够的。

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

如何使用它:

var port  = "ÀÂÃÁÉÊÍÓÔÕÜÚÇáàãâêéíóõôúüç";
var ascii = "AAAAEEIOOOUUCaaaaeeiooouuc";
console.log(tr("não têm ações em seqüência", port, ascii)) ;

答案 8 :(得分:0)

类似于乔纳森·洛诺夫斯基(Jonathan Lonowski)的答案,但带有单词支持,而不仅仅是单个tr字符

"aaabbccddeeDDDffd".replace( /(a|cc|DDD|dd)/g, m => ({'a':'B', 'cc':'DDD', 'DDD':'ZZZ', dd:'QQ'}[m]) ) 
// RESULT: "BBBbbDDDQQeeZZZffd"