【问题标题】:How do you map-replace characters in Javascript similar to the 'tr' function in Perl?你如何在 Javascript 中映射替换字符,类似于 Perl 中的 'tr' 函数?
【发布时间】:2012-05-30 09:31:02
【问题描述】:

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

我找到了this site that shows equivalent functions in JS and Perl,但遗憾的是没有对应的 tr。

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

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

会映射

     - => + and _ => /

如何在 JavaScript 中有效地做到这一点?

【问题讨论】:

标签: javascript perl character-encoding transliteration


【解决方案1】:

这会将所有as 映射到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('');

【讨论】:

  • 为什么在不测试的情况下发布答案,为什么在编辑后保留无效的答案?
【解决方案2】:

没有内置的等价物,但您可以使用replace 接近:

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

【讨论】:

  • 很不错的回调函数,return{..}[m] 有什么作用?
  • @qdeninja 对象 ({...}) 定义字符映射,预期匹配作为键/属性,替换作为值。然后使用当前匹配 m 从对象中查找其自己的替换 ([m]),然后返回到 replace 以执行实际替换。
  • 显然答案是“是”,但不如 Perl 简洁。
  • 当我们有一个数组arr 充满了这样的替换,并且匹配遵循一个可以完全由正则表达式给出的简单模式时,最好有一个默认值,以防正则表达式有点一般并匹配不在arr 中的东西。在这种情况下,函数体应该是return arr[m] || m;,只返回匹配本身而不进行任何替换(而不是undefined)。
  • 不确定这个的性能,但是将对象(“字典”)定义为全局变量可能会更快(避免每次都重新创建)。
【解决方案3】:

在Perl中也可以写

tr{-_}{+/}

作为

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

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

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

后一个版本肯定可以用 JS 实现,没有太多麻烦。

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

【讨论】:

    【解决方案4】:

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

    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 },回调返回 hash[ chr ]。

    【讨论】:

    【解决方案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!"
    

    【讨论】:

    • @qdeninja 这是相同的技术,而这种方法允许使用动态 JSON kv 映射。它可能比答案慢,因为它会为您生成正则表达式和替换字典。所以在需要动态替换的时候使用这个方法,如果只需要处理静态词集就使用答案。
    【解决方案6】:

    这个函数,类似于它在 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($_);

    【讨论】:

    • 似乎是最好的答案...但请更好地解释什么是s() 以及如何使用tr()。理想只有一个函数tr(x,from,to)。
    【解决方案7】:

    我想要一个允许传递自定义地图对象的函数,所以我根据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
    

    【讨论】:

      【解决方案8】:

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

      对于必须仅用一个替换多个字符或反之亦然的情况,Is 不够好。从葡萄牙语文本中删除重音还不够好,这是我的用例。

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

      【讨论】:

        【解决方案9】:

        类似于 Jonathan Lonowski 的回答,但有文字支持,而不仅仅是单个 tr 字符

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

        【讨论】:

          猜你喜欢
          • 2019-04-14
          • 2018-05-01
          • 2018-09-10
          • 1970-01-01
          • 2021-09-23
          • 2020-04-10
          • 1970-01-01
          • 1970-01-01
          • 2012-07-24
          相关资源
          最近更新 更多