正则表达式负面lookbehind在JavaScript中无效

时间:2016-02-01 23:24:20

标签: javascript regex regex-lookarounds

考虑:

var re = /(?<=foo)bar/gi;

这是Plunker中无效的正则表达式。为什么呢?

2 个答案:

答案 0 :(得分:13)

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" } (否定),但这并不意味着您仍然无法实现此类JavaScript中的逻辑。

匹配(非全局)

正面观察比赛:

// from /(?<!foo)bar/i
var matcher = mystring.match( /(?!foo)(?:^.{0,2}|.{3})(bar)/i );
if (matcher) {
  // do stuff with matcher[1] ("bar"), knowing that it does not follow "foo"
}

固定宽度负后观匹配:

(?!foo).{3}(bar)

负面的外观可以在没有全局标志的情况下完成,但只有固定的宽度,必须计算宽度(使用lookbehinds可能会变得困难)。使用.会更简单,大致相同,但它不会匹配以&#34; rebar&#34;开头的行。由于break无法匹配换行符,因此我们需要上述代码的替换来匹配以&#34; bar&#34;在角色四之前。

如果您需要宽度可变,请使用以下全局解决方案,并在if节的末尾添加g。 (此限制很常见。alternations.NETvimJGsoft正则表达式引擎,支持可变宽度的后视。only,{{3}并且PCRE仅限于固定宽度。PHP需要Perl来支持此功能。也就是说,下面的解决方法的逻辑适用于所有支持正则表达式的语言。)< / p>

匹配(全局)

当你需要循环给定字符串中的每个匹配(matcher修饰符,全局匹配)时,你必须在每个循环迭代中重新定义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" } 变量,你必须使用{{3 (使用RegExp创建Python)因为alternate regex module解释了全局修饰符RegExp.exec()并将创建一个无限循环!

全球积极的看法:

var re = /(foo)?bar/gi;  // from /(?<!foo)bar/gi
while ( matcher = re.exec(mystring) ) {
  if (!matcher[1]) {
    // do stuff with matcher[0] ("bar"), knowing that it does not follow "foo"
  }
}

&#34;东西&#34;当然可以包括填充数组以供进一步使用。

Global Negative lookbehind:

/(?<!ba)ll/g

请注意,before the loop中没有完全代表负面看法的String.match()。考虑Fall ball bill balll llamaballl匹配。它只会找到所需的四个匹配中的三个,因为当它解析ball时,会找到l llama,然后在balll后面继续一个字符。只有当末尾的部分匹配可能会干扰另一端的部分匹配时才会出现这种情况((ba)?ll休息foobarbar(foo)?barString.replace()一样好)唯一解决方案这是使用上述固定宽度的方法。

更换

有一篇名为differently的精彩文章描述了如何做到这一点。
它甚至有一个跟进指向cases,在JS中实现这一点。

g中实现lookbehind要容易得多,因为你可以创建一个Mimicking Lookbehind in JavaScript作为替换,并处理该函数中的lookbehind逻辑。

这些可以在第一场比赛中使用,但只需添加// assuming you wanted mystring.replace(/(?<=foo)bar/i, "baz"): mystring = mystring.replace( /(foo)?bar/i, function ($0, $1) { return ($1 ? $1 + "baz" : $0) } ); 修饰符即可实现全局化。

正面看后替换:

bar

这将获取目标字符串,并将baz的实例替换为foo,只要它们跟随$1即可。如果是,则bar匹配,三元运算符(collection of short functions)返回匹配的文本和替换文本(但不是// 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说{I},因为我们知道{{ 1}}是空的。

这与其他动态宽度负向后视解决方法具有相同的警告,并且通过使用固定宽度方法进行类似修复。

答案 1 :(得分: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);