我正在使用正则表达式创建一个简单的模式匹配器,它可以采用我的正则表达式模式,并以我想要的格式生成一个新的字符串。当我注意到我有相邻的正则表达式模式与彼此冲突时,看起来像一个简单的程序变得非常复杂,并且无法再正确执行操作,因为新形成的字符串包含与我刚刚替换的字符冲突的字符...(我知道它可能有点混乱,所以我提供一个例子)。
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"
。我曾想过使用源图,引用正则表达式的地图并执行自定义替换函数,该函数引用地图以在正确的位置执行替换....但我似乎无法掌握源图实现这一点....任何帮助将不胜感激。
答案 0 :(得分:0)
正如我在第一次更换时所看到的那样,将你更换为 am ,所以在第二次更换所有i时,这意味着你不仅要更换“我”和“它”“我”。也是,所以你得到你写的结果。 这是正则表达式,无法替换标签“i”:
r2 = /(i)[^>]/ig
答案 1 :(得分:0)
你可以想出一些你期望在字符串中找不到的字符序列,使用该序列暂时包装你所有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标记,但这个顺序可能还不够。但您现在应该可以轻松修改seq
,replaceFunc
和/或绑定replaceFunc
的对象以满足您的需求。
这里是JSFiddle。祝你好运!