将前瞻和后视统一为一个正则表达式运算符

Unifying lookahead and lookbehind into a single regex operator

我正在为 regex 制作一个 simplified/sugary 包装器,它删除了许多更复杂的 regex 函数(同时仍然保留 99% 的使用的基本要素),并且还试图整理语法 a很少。

关于否定 lookahead/lookbehind,我发现为什么不能将它们组合成一个函数令人困惑。为了阐明我的意思,让我用一个例子来证明:

我知道如果你不想匹配前面有 "giz" 的 "mo",你会使用负后视。所以表达式 (?<!giz)mo 会处理这个问题。

而且我知道,如果您不想匹配 "giz" 后面跟有 "mo" 的部分,那么您可以使用否定前瞻。所以表达式 giz(?!mo) 将处理这个问题。

我不知道的是为什么正则表达式无法自己解决这个问题。理论上,我不需要指定它是领先还是落后 - 它应该只查看不允许的位,并排除包含该位的任何表达式。

为了进一步阐明并可能证明我的观点,我可能会用我的糖衣来解释我自己的自定义用途符号 - ⊄ 和 ⊅ - 就像这样:

...将此:giz⊄mo⊅ 替换为:giz(?!mo)(?<!mo)

...并将此:⊄giz⊅mo 替换为:(?!giz)(?<!giz)mo

如您所见,在这两种情况下,它都使用了前瞻和后视,因此用户不必决定使用哪一个。你可能会说用户很懒惰,但我只能说 Regex 很懒惰,因为它没有在幕后这样做。

用另一种方式重述这个问题,你可以用 (?!xyz) and/or (?<!xyz) 做哪些你不能用单曲做的实际事情:(?!xyz)(?<!xyz)?为什么 Regex 需要两个运算符才能明显地执行一个本质上的功能?

我使用的是 .NET,所以 lookbehind 具有全面的多功能性。

我是不是漏掉了什么?

恐怕你没有抓住重点。

后视检查模式中位置之前的字符,先行检查模式中之后的字符。

abc(?!xyz) 检查 abc 后面是否没有 xyz,这是有道理的:看不到与 abcxyzz here 的匹配)。

(?<!xyz)abc 将检查 abc 之前的字符,并且在 abcxyzz 中有一个匹配项(参见 here)。

现在,在 abc(?!xyz)(?<!xyz) 中,(?<!xyz) 没有意义,因为它始终为真(我们有 abc,而不是 xyz)。 abc(?!xyz)(?<!xyz) = abc(?!xyz).

(?!xyz)(?<!xyz)abc 中,(?!xyz) 部分始终为真,因为 abc 不是 xyz(?!xyz)(?<!xyz)abc = (?<!xyz)abc.

按照您建议的方式使用前瞻和后视是没有意义的,它只会增加开销并降低性能,不会带来统一,但会给引擎带来痛苦。

您可能想要 (?!xyz) 而不是 (?!xyz)(?<!xyz) 的一个简单示例是在正则表达式 xyz(?!xyz) 中,以匹配未紧随其后的 xyz另一个 xyz。用 xyz(?!xyz)(?<!xyz) 试一下,你会发现它永远不会匹配:检查 (?<!xyz) 的点总是在 xyz 之前,因为你刚刚匹配了它。

理论上,很容易说:"Well, just get the program to automatically decide the direction based on the position of any adjacent literals",所以(?<!xyz)house.*(?<!xyz)househouse(?!xyz)house(?!xyz).*都有意义。规则将是 "If the literal is to the left, use the lookahead operator, whilst if it's to the right, then use the lookbehind operator."。如果双方都是字面意思,那么这个表达式无论如何都毫无价值。这保持了 most 的时间(尽管正如 hvd 所指出的,如果 xyz 中的字符数与 ISN' 的相邻文本中的字符重叠,它将不起作用T 文字 - 例如:(?!xyz)xy*z).

中的星号

但当双方都不是文字时,进一步的问题就会出现。

例如,尝试使用正则表达式:the ..(?!u).. house 对文本 "the blue house"。显然,?! 与此处的 ?<! 行为不同,可能需要任何一个选项。