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

考虑:

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

它是Plunker中的无效正则表达式.为什么?

最佳答案
JavaScript缺乏对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"), knowing that it does not follow "foo"
}

负面观察可以在没有全局标志的情况下完成,但只能使用固定宽度,并且您必须计算该宽度(使用alternations可能会变得困难).使用(?!foo).{3}(bar)会更简单,大致相同,但它不会匹配以“rebar”开头的行.无法匹配换行符,因此我们需要上面的代码交替来匹配字符四之前的“bar”行.

如果您需要宽度可变,请使用以下全局解决方案,并在if节的末尾放置一个中断. (这种限制很常见..NET,vimJGsoft是支持可变宽度后视的only正则表达式引擎.PCRE,PHPPerl限制为固定宽度.Python需要alternate regex module支持这个.那就是说,逻辑到下面的解决方法适用于支持正则表达式的所有语言.)

匹配(全球)

当你需要循环给定字符串中的每个匹配(g修饰符,全局匹配)时,你必须在每个循环迭代中重新定义匹配器变量,你必须使用RegExp.exec()(使用RegExp创建before the loop),因为String.match()解释了全局修饰符differently并将创建一个无限循环!

全球积极的观察背后:

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"
}

“Stuff”当然可以包括填充阵列以供进一步使用.

全球负面观察:

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"
  }
}

请注意,有cases,这将不能完全代表负面的背后.考虑/(?<!ba)ll / g匹配Fall ball bill balll llama.它只能找到所需的四个匹配中的三个,因为当它解析balll时,它会找到球,然后在l lmama后面继续一个角色.这种情况只发生在最后的部分匹配可能会干扰不同端的部分匹配时(balll break(ba)?ll但foobarbar与(foo)相符?bar)唯一的解决办法是使用上面修复的宽度法. 更换 有一篇名为Mimicking Lookbehind in JavaScript的精彩文章描述了如何做到这一点.
它甚至有一个跟进指向collection of short functions,在JS中实现这一点.

在String.replace()中实现lookbehind更容易,因为您可以创建一个anonymous function作为替换并处理该函数中的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) }
);

这将获取目标字符串并用baz替换bar的实例,只要它们遵循foo即可.如果是,则匹配$1,三元运算符(?:)返回匹配的文本和替换文本(但不是条形部分).否则,三元运算符返回原始文本.

消极的后视替换:

// 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是空的).

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

转载注明原文:正则表达式负面lookbehind在JavaScript中无效 - 代码日志