考虑:
var re = /(?<=foo)bar/gi;
这是 Plunker 中无效的正则表达式。为什么?
考虑:
var re = /(?<=foo)bar/gi;
这是 Plunker 中无效的正则表达式。为什么?
2020 年更新: Javascript 实现开始原生支持正则表达式lookbehinds。一种用于建议草案正则表达式向后断言,接受对ECMA-262规范草案为2021的ECMAScript,被实施在V8的Irregexp在铬6 2+(释放二○一七年十月一十七日)和已经通过一个拾取垫片层为Firefox 78+ 中的 Irregexp(ESR,2020 年 6 月30日发布)。其他 JS 解释器将跟随。
JavaScript 缺乏对(positive) 和(negative) 之类的正则表达式lookbehinds 的支持,但这并不意味着您仍然不能在 JavaScript 中实现这种逻辑。(?<=…)
(?<!…)
// from /(?<=foo)bar/i
var matcher = mystring.match( /foo(bar)/i );
if (matcher) {
// do stuff with matcher[1] which is the part that matches "bar"
}
// from /(?<!foo)bar/i
var matcher = mystring.match( /(?!foo)(?:^.{0,2}|.{3})(bar)/i );
if (matcher) {
// do stuff with matcher[1] ("bar"), which does not follow "foo"
}
负向后视可以在没有全局标志的情况下完成,但只能使用固定宽度,并且您必须计算该宽度(这可能会因交替而变得困难)。使用(?!foo).{3}(bar)
会更简单且大致等效,但它不会匹配以“rebar”开头的.
行,因为无法匹配换行符,因此我们需要替换上面的代码以匹配字符 4 之前具有“bar”的行。
如果您需要可变宽度,请使用以下全局解决方案并break
在if
节的末尾放置 a 。(此限制是相当普遍的。 .NET,VIM,和JGsoft是唯一的正则表达式引擎宽度回顾后发。支持可变 PCRE,PHP,和Perl中被限制为固定的宽度。 Python中需要一个备用module的正则表达式来支持这一点。这就是说,以下解决方法的逻辑应该适用于支持正则表达式的所有语言。)
当您需要在给定字符串(g
修饰符,全局匹配)matcher
中的每个匹配上循环时,您必须在每次循环迭代中重新定义变量,并且您必须使用RegExp.exec()
(在循环之前创建的 RegExp ),因为String.match()
对全局修饰符的解释不同,并且会造成无限循环!
var re = /foo(bar)/gi; // from /(?<=foo)bar/gi
while ( matcher = re.exec(mystring) ) {
// do stuff with matcher[1] which is the part that matches "bar"
}
“东西”当然可以包括填充一个数组以供进一步使用。
var re = /(foo)?bar/gi; // from /(?<!foo)bar/gi
while ( matcher = re.exec(mystring) ) {
if (!matcher[1]) {
// do stuff with matcher[0] ("bar"), which does not follow "foo"
}
}
请注意,在某些情况下,这不能完全代表负面的后视。考虑/(?<!ba)ll/g
匹配Fall ball bill balll llama
. 它只会找到所需的四个匹配项中的三个,因为当它解析时balll
,它会在 处找到ball
然后继续一个字符l llama
。这只发生在末尾的部分匹配可能会干扰另一端的部分匹配(balll
中断(ba)?ll
但foobarbar
很好(foo)?bar
)时,唯一的解决方案是使用上述固定宽度方法。
Mimicking Lookbehind in JavaScript是一篇很好的文章,描述了如何做到这一点。
它甚至还有一个后续,指向一系列在 JS 中实现这一点的短函数。
实现lookbehindString.replace()
要容易得多,因为您可以创建一个匿名函数作为替代并处理该函数中的lookbehind逻辑。
这些适用于第一场比赛,但可以通过仅添加g
修饰符来实现全局化。
// assuming you wanted mystring.replace(/(?<=foo)bar/i, "baz"):
mystring = mystring.replace( /(foo)?bar/i,
function ($0, $1) { return ($1 ? $1 + "baz" : $0) }
);
这需要目标字符串并替换bar
with 的实例,baz
只要它们跟随foo
。如果$1
匹配,则匹配并且三元运算符 ( ?:
) 返回匹配的文本和替换文本(但不是bar
部分)。否则,三元运算符返回原始文本。
// assuming you wanted mystring.replace(/(?<!foo)bar/i, "baz"):
mystring = mystring.replace( /(foo)?bar/i,
function ($0, $1) { return ($1 ? $0 : "baz") }
);
这本质上是一样的,但由于它是一个负面的后视,它在$1
缺失时起作用(我们不需要在$1 + "baz"
这里说,因为我们知道$1
是空的)。
这与其他动态宽度负向后视解决方法具有相同的警告,并且通过使用固定宽度方法类似地修复。
这是一种在 JS 中使用 DOM 解析 HTML 字符串并仅在标签之外执行替换的方法:
var s = '<span class="css">55</span> 2 >= 1 2 > 1';
var doc = document.createDocumentFragment();
var wrapper = document.createElement('myelt');
wrapper.innerHTML = s;
doc.appendChild( wrapper );
function textNodesUnder(el){
var n, walk=document.createTreeWalker(el,NodeFilter.SHOW_TEXT,null,false);
while(n=walk.nextNode())
{
if (n.parentNode.nodeName.toLowerCase() === 'myelt')
n.nodeValue = n.nodeValue.replace(/>=?/g, "EQUAL");
}
return el.firstChild.innerHTML;
}
var res = textNodesUnder(doc);
console.log(res);
alert(res);