最近我意识到(有点尴尬),在 Javascript
中无法使用正则表达式的 lookbehind assertions
。
为什么这个看似普遍的断言被禁用了呢?
我知道可能有其他方法来实现相同的功能,但是是基本语义禁止了这个功能,还是怎么回事呢?
同时,一些正则表达式测试工具似乎忽略了这个事实,并生成了Javascript代码——这对我来说有点奇怪。
最近我意识到(有点尴尬),在 Javascript
中无法使用正则表达式的 lookbehind assertions
。
为什么这个看似普遍的断言被禁用了呢?
我知道可能有其他方法来实现相同的功能,但是是基本语义禁止了这个功能,还是怎么回事呢?
同时,一些正则表达式测试工具似乎忽略了这个事实,并生成了Javascript代码——这对我来说有点奇怪。
回溯断言现已成为ES 2018规范的官方部分。Axel Rauschmayer在他的博客文章中给出了很好的介绍。
看起来当时Brendan Eich还不知道它的存在(因为Netscape是建立在旧版本的Perl上):
这是1998年,我在'97年做的Netscape 4工作是基于Perl 4(!)的,但我们向ECMA TC39 TG1(JS组-当时情况不同,包括大小写)提出了一些基于Perl 5的建议。我们没有得到所有内容,而且我们不得不解决一些明显的怪癖问题。 我不记得后向引用(在Perl 5.005中于1998年7月出现)被有意地省略了。Waldemar可能会记得更多,我将JS密钥交给了他,在netscape.com内部进行mozilla.org的操作。 如果你愿意写一个提案或迷你规范(甚至是ES5风格的),请告诉我。我下周将与其他TC39成员进行讨论。 /be邮件列表中已经有多个关于尝试包含它的讨论,但从性能角度来看,这似乎仍然是一个相当复杂的功能,因为EcmaScript正则表达式是基于回溯的,并且在使用捕获组时需要在后面进行回溯。如果使用不当,这可能会导致灾难性回溯等问题。
在某个时候,它被建议用于ES6/Es 2015,但它从未成为草案,更别提规范了。在讨论的最后一篇帖子中,似乎没有人接手实现它。如果有人感觉有兴趣编写实现,他们可以注册ES Discuss列表并提出建议。
2015年5月,Nozomu Katō提出了ES7后行实现。
正则表达式后行被添加为阶段0建议。
该提案现在处于第3阶段。这意味着至少需要有两个浏览器来实现它才能成为下一个EcmaScript标准的一部分。正如@martixy在评论中提到的那样,Chrome已经在JS实验标志后面实现了它。
(?<=fixed-string)
(?<=a|fixed|string)
(?<=t[abc]{1,3})
(?<=(abc){2,6})
(?<=^.*abc.*)
(?<=\G"[^"]+");
(?<=^(.....|.......)+)
\b(\w+)\b(?<!\b\1\b.*\1)
(?<=fixed-string)
,任何一个后顾断言实现都必须支持,(?<=a|fixed|string)
是更加理想的情况。
不同的正则表达式引擎对上述正则表达式的支持程度各不相同。
让我们看看它们在 .NET 和 Java 中是如何实现的。(这是我研究过的两种风格的后顾行为。)
在 Microsoft .NET 实现中,所有这些正则表达式都是有效的,因为 .NET 使用从右到左模式实现后顾断言,并以当前位置为起始偏移量。后顾构造本身不会生成任何选择点。
然而,如果在后顾断言内使用捕获组,就会变得混乱,因为模式中的原子是从右到左解释的,如本文所示。这是这种方法的缺点:写后顾断言时需要将思维包装成从右到左。
正如您所见,添加对反向前瞻的支持并不容易:
(请注意,我尚未涵盖反向前瞻在反向后瞻内部使用以及反之的行为。在定义反向前瞻结构的语义时,这也应该考虑在内)。
这些技术障碍也被 Waldemar Horwat(编写 ES3 正则表达式规范的人)在 邮件 中提到,在 nils' answer 中引用:
没有人提交过一个关于回顾前瞻的明确定义提案。回顾前瞻很难翻译成规范使用的语言,并且在正则表达式的部分评估顺序很重要时会变得非常模糊,这就是如果涉及捕获括号时会发生的情况。你从哪里开始寻找回顾前瞻?最短的先,最长的先,还是反向字符串匹配?贪婪还是不贪婪?回溯到捕获结果中去?Javascript
处理 regex
的方式有些低效,并且他们不太可能为此实现后顾断言,对吗? - l'L'l
Javascript
代码。每次使用该网站时,我似乎都完全忽略了切换到正确的规范。它不是唯一一个似乎允许您使用错误的规范并生成(无效)代码的工具。 - l'L'l