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

multiple conflicting regex replacements on string in javascript

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

var str = "I am the greatest";
var r1 = /(am)/g;
var r2 = /(i)/ig;
var newstr = str.replace(r1,"<i></i>").replace(r2,"<h1></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 来引用正则表达式的地图并执行自定义替换功能,该功能引用地图以在正确的位置执行替换....但我似乎无法充分了解 sourcemaps 以实现这....任何帮助将不胜感激。

正如我在你的第一次替换中看到的那样,你将 am 替换为 am,所以在第二次你替换了所有 i,这意味着你不仅替换了 "I" 并且<"i">,所以你得到你写的结果。 这是正则表达式,无法替换标签 "i":

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

您可以想出一个您永远不会在字符串中找到的字符序列,使用该序列暂时包装所有 replacements 的结果,然后最终去除该序列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></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, ''); // strip the sequence, leaving the desired string

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

这是一个 JSFiddle。祝你好运!