【问题标题】:JavaScript - From an optimization standpoint how should one replace multiple substrings in a string with different strings?JavaScript - 从优化的角度来看,应该如何用不同的字符串替换字符串中的多个子字符串?
【发布时间】:2023-04-02 06:50:01
【问题描述】:

在我开发和维护的代码中,我遇到了问题。

我有一个函数,它接受一个查询(类型字符串)并用不同的字符串替换该字符串的子字符串。例如,如果用户输入字符串I have a cat,它将替换为I have a dog

我的代码有效,但问题是我有数百个这样的子字符串需要替换为不同的子字符串。它在美学上看起来也很糟糕。

var myString;
myString = myString.replace('cat','dog')
                   .replace('elephant','zebra')
                   .replace('bird','fish')
                   // Goes on for hundreds of lines

这一切都在一个函数中,每次调用它都会经历数百次replace 调用。

我可以尝试做的一件事是创建一个对象数组并遍历它。代码看起来像这样。

var animalsArray = [
                       {'a':'cat','b':'dog'},
                       {'a':'elephant','b':'zebra'},
                       {'a':'bird','b':'fish'}
                   ];

然后在我的函数中

function stringReplace(string) {
    for (var i = 0; i < animalsArray.length; i++) {
        if (string.indexOf(animalsArray[i]['a']) > -1) {
            sting = string.replace(animalsArray[i]['a'],animalsArray[i]['b']);
        }
    }
}

但我不确定这是否会改善我目前将数百个替换调用链接在一起的做法。

我基本上是在优化我当前的代码。最佳做法是什么?

【问题讨论】:

    标签: javascript string optimization replace substring


    【解决方案1】:

    我会考虑改用一个对象,其键是要替换的子字符串,其值是替换。通过交替对象的所有键来创建正则表达式,然后使用替换函数查找对象上的关联值:

    const replacements = {
      cat: 'dog',
      elephant: 'zebra',
      bird: 'fish'
    };
    const pattern = new RegExp(Object.keys(replacements).join('|'), 'g');
    console.log('Foo cat bar bird'.replace(pattern, match => replacements[match]));

    使用对象语法可以轻松添加/删除项目。如果你想让它更容易修改,你可以考虑将替换信息放入一个字符串中,然后将其解析为一个对象:

    const replacementsStr = `
    cat        dog
    elephant   zebra
    bird       fish
    `;
    
    const replacements = Object.fromEntries(
      replacementsStr
        .trim()
        .split('\n')
        .map(line => line.split(/\s+/))
    );
    const pattern = new RegExp(Object.keys(replacements).join('|'), 'g');
    console.log('Foo cat bar bird'.replace(pattern, match => replacements[match]));

    【讨论】:

    • 显然RegExp 已经在浏览器中进行了高度优化,但我想知道indexOfsubstring 的解决方案可能会如何处理它,尽管需要更多代码。另见stackoverflow.com/questions/5296268/…
    • 使用indexOf 需要调用indexOf 来进行每个 可能的替换,以及每个 可能的字符索引组合来进行每个可能的替换(例如,对于“猫”,索引 0-2,然后是索引 1-3,然后是索引 2-4,等等。如果找到匹配项,请再次执行相同操作,直到找不到更多匹配项。然后执行相同操作下一个替换的东西,其中有数百个)。可能效率更低,更混乱。
    【解决方案2】:

    你可以用一堆 or 语句组成一个正则表达式。 (dog|elephant|bird|....) 这将允许您运行一项检查。替换为您提供匹配的文本,您可以使用它来查找要替换的单词。

    所以创建一个要替换的字符串对象,它们的值就是要替换的单词。您可以通过匹配的键查找替换。

    const animals = {
      cat: 'dog',
      elephant: 'zebra',
      bird: 'fish',
    }
    
    // build the or sting with a simple join
    const keysString = Object.keys(animals).join("|")
    // generate the regular expression to match the words
    var animalRE = new RegExp(`\\b(${keysString})\\b`,'g');
    
    // a sample string to match
    const myString = "I like to pet a cat that looks like an elephant that moves like a bird."
    
    // the replacement step. The function takes the matched text (aka key) and looks it up in the object
    const updated = myString.replace(animalRE, key => animals[key] || key)
    
    // display the new string
    console.log(updated)

    【讨论】:

    • 不错的解决方案!只要单词(或短语)不包含任何特殊的正则表达式字符,它就可以正常工作。几个月前我做了类似的事情,做了一些比较对象和地图的分析,地图要快得多(至少在我测试的唯一环境 Chrome 和 Node 中)
    【解决方案3】:

    我会这样做:

    function WordSwapper(sentence){
      const swapper = sentence;
      this.swaps = [];
      this.add = (word, replacer)=>{
        this.swaps.push([word, replacer]);
        return this;
      }
      this.swap = (sentence = null)=>{
        let s = sentence === null ? swapper : sentence;
        this.swaps.forEach(a=>{
          s = s.replace(new RegExp(a[0], 'gi'), a[1]);
        });
        return s;
      }
    }
    const ws = new WordSwapper('The cat plays. Elephants live in the Serengeti. Have you ever seen a bird fly?');
    ws.add('cat', 'dog').add('elephant', 'zebra').add('bird', 'fish');
    console.log(ws.swap());

    当然,您可能想要对复数和大写情况做一些事情。

    【讨论】:

    • 我非常感谢您的回复。大写和复数很容易,但这超出了这个问题的范围。
    猜你喜欢
    • 2015-11-09
    • 2022-12-15
    • 2011-09-01
    • 2017-12-06
    • 2022-01-22
    • 2016-09-10
    • 2020-08-31
    • 2021-06-13
    相关资源
    最近更新 更多