javascript中字符串上的多个正则表达式替换冲突

multiple conflicting regex replacements on string in javascript

本文关键字:正则表达式 替换 冲突 字符串 javascript      更新时间:2023-09-26

我正在使用regex制作一个简单的模式匹配器,它可以接受我的regex模式,并以我想要的格式生成一个新字符串。当我注意到我有相邻的regex模式相互冲突,并且无法再正确执行操作时,起初看似简单的程序变得非常复杂,因为新形成的字符串包含的字符会与我刚刚替换的内容冲突。。。(我知道这可能有点令人困惑,所以我将提供一个例子)。

var str = "I am the greatest";
var r1 = /(am)/g;
var r2 = /(i)/ig;
var newstr = str.replace(r1,"<i>$1</i>").replace(r2,"<h1>$1</h2>");
console.log(newstr);
    //returns "<h1>I</h2> <<h1>i</h2>>am</<h1>i</h2>> the greatest"

我知道这是一个天真的例子,但它完美地说明了我的观点。我希望发生的是,第二个(以及所有正在进行的)替换对原始字符串执行匹配,但对变异字符串执行替换,以便上例中的newstr var读取"<h1>I</h2> <i>am</i> the greatest"。我已经考虑过使用sourcemaps来引用regexs的映射,并执行一个自定义替换函数,该函数引用映射来在正确的位置执行替换。。。。但我似乎无法掌握足够的源地图来实现这一点。。。。任何帮助都将不胜感激。

您可以想出一个在字符串中永远找不到的字符序列,使用该序列临时包装所有replace项的结果,然后在所有replace项完成后剥离该序列。

例如,选择#{...}的序列,您需要将其添加到所有正则表达式模式中。类似于:

var seq = /#'{(.*?)'}/g; // our sequence -- #{...}
// Prepend (#'{(.*?)'})| to the given regex
var newExpression = function(regex) {
    var splitRegex = regex.toString().split('/'),
        flags = splitRegex.pop();
    splitRegex.shift(); // get rid of the first blank entry from the opening '/' in the regex
    return new RegExp('(' + seq.toString().slice(1, -2) + ')|' + splitRegex.join('/'), flags);
};
var r1 = newExpression(/(am)/g); // returns /(#'{(.*?)'})|(am)/g
var r2 = newExpression(/(i)/ig); // returns /(#'{(.*?)'})|(i)/ig

如果您不想手动将(#'{.*?'})|添加到所有模式的开头,可以这样做。我们这样做是为了在随后的通行证中识别这个序列,而不是触摸它

接下来,确保在所有比赛的开始处粘贴#{,在比赛结束时粘贴}

str.replace(r1, '#{<i>$1</i>}')...

将实现这一目标。不幸的是,这对我们来说还不够智能——我们需要单独保留与序列(#{...})匹配的项目;换句话说,用它们自己来代替它们。这里有一个功能可以很好地为我们做到这一点:

var replaceFunc = function(match) {
    return match.match(seq)
        ? match
        : '#{<' + this.tag + '>' + match + '</' + this.tag + '>}';
};

然后像这样使用:

var newStr = str.replace(r1, replaceFunc.bind({tag: 'i'}))
    .replace(r2, replaceFunc.bind({tag: 'h1'}))
    .replace(seq, '$1'); // strip the sequence, leaving the desired string

当然,我知道在实际实现中不一定要使用HTML标记,而且这个序列可能还不够。但是,您现在应该能够轻松地修改seqreplaceFunc和/或绑定replaceFunc的对象,以满足您的需要。

这是一个JSFiddle。祝你好运!

正如我在你的第一次替换中看到的,你将am替换为am,所以在第二次替换所有I时,这意味着你不仅替换了"I"和<"i">,所以你得到了你写的结果。这是regexp,它不能取代标签"i":

r2 = /(i)[^>]/ig