正则表达式顺序
回答
当教程介绍lookarounds,他们往往会选择每一个最简单的使用情况。因此,他们会使用(?<!a)b
('b''之前未加'a')或q(?=u)
('q'后加'u')的示例。这只是为了避免让注意力分散的细节混淆解释,但它倾向于创造(或加强)这样的印象,即往后看和向后看起来应该以某种顺序出现。我花了相当长的时间来克服这个想法,而且我也看到其他几个人也受到了这个问题的困扰。
试着看一些更实际的例子。一个涉及很多问题涉及验证密码;例如,确保新密码长度至少为六个字符并且至少包含一个字母和一个数字。要做到这一点的方法之一是:
^(?=.*[A-Za-z])(?=.*\d)[A-Za-z0-9]{6,}$
的字符类[A-Za-z0-9]{6,}
可以匹配所有字母或所有数字,让你用的向前看符号,以确保有各自的至少一个。在这种情况下,您必须首先执行,因为正则表达式的后面部分必须能够检查整个字符串。
又例如,假设您需要查找单词“there”的所有出现位置,除非其前面带有引号。显而易见的正则表达式是(?<!")[Tt]here\b
,但是如果您搜索的是大型语料库,那可能会造成性能问题。正如所写的那样,该正则表达式将在文本中的每一个位置都做负面的后台关系,并且只有当它成功时才会检查正则表达式的其余部分。
每一个正则表达式引擎都有自己的长处和短处,但其中的一点是,它们更快地找到文字字符的固定序列,而不是其他任何东西 - 序列越长越好。这意味着它可以大大加快做回顾后最后,即使这意味着这个词两次匹配:
[Tt]here\b(?<!"[Tt]here)
所以管理lookarounds的位置,规则是没有规则;你把它们放在最有意义的地方。
1(?=ABC)
表示 - 查找1
,并且匹配(但不捕获)后面的ABC
。
(?<=ABC)1
表示在当前位置之前匹配(但不捕获)ABC
,并继续匹配1
。
因此,通常情况下,您会在前面的表达式和后面的后面放置向前看。
当我们在表达式后面放置一个倒序时,我们正在重新检查我们已经匹配的字符串。当你有复杂的条件时,这很常见(你可以把它想象成AND
的正则表达式)。例如,拿在最近这次的回答看看由Daniel Brückner:
.&.(?<! &)
首先,你捕获两个字符之间的符号。接下来,你检查他们是不是空格(\S&\S
不会在这里工作,OP想要捕获1&_
)。
我觉得在示例中比解释更容易。让我们这个表达式:
(?<=\d)(?=(.)\1)(?!p)\w(?<!q)
这意味着:
(?<=\d)
- 确保赛前位置是一个数字会发生什么。(?=(.)\1)
- 确保我们在这个(相同)位置匹配的任何字符后面跟着一个自身副本(通过反向引用)。(?!p)
- 确保接下来不是p
。\w
- 匹配字母,数字或下划线。请注意,这是我们第一次真正匹配并使用角色。(?<!q)
- 确保我们迄今为止匹配的内容不会以q
结尾。
所有这一切都将匹配像abc5ddx
或9xx
但不5d
或6qq
或asd6pp
或add
字符串。请注意,每个断言独立工作。它只是停下来,环顾四周,如果一切顺利的话,让匹配继续下去。
还要注意的是,在大多数(可能全部)实现中,lookbehinds具有固定长度的限制。您不能在其中使用重复/可选性运算符,如?
,*
和+
。这是因为要匹配一个模式,我们需要一个起点 - 否则我们必须尝试匹配字符串中每个点的每个后视图。
此正则表达式的串a3b5ddx
的样品运行如下:
- 文本光标位置:0
- 尝试第一回顾后在位置匹配-1(因为
\d
总是匹配1个字符)。我们不能匹配负指数,所以失败并提前光标。
- 尝试第一回顾后在位置匹配-1(因为
- 文本光标位置:1.
- 尝试匹配位置0
a
第一回顾后不匹配\d
如此失败,再次向前移动光标。
- 尝试匹配位置0
- 文本光标位置:2
- 尝试在第一回顾后在位置1
3
匹配不匹配\d
所以保持光标不变,并且继续匹配。 - 尝试匹配位置2处的第一个预测。
b
匹配(.)
并被捕获。5
不匹配\1
(这是被捕获的b
)。因此,失败并推进游标。
- 尝试在第一回顾后在位置1
- 文本光标位置:3
- 尝试匹配在2位
b
第一回顾后不匹配\d
如此失败,再次向前移动光标。
- 尝试匹配在2位
- 文本光标位置:4
- 尝试在第一回顾后在位置3
5
匹配不匹配\d
所以保持光标不变,并且继续匹配。 - 尝试匹配位置4处的第一个预测。
d
匹配(.)
并被捕获。第二个d
确实匹配\1
(这是第一个捕获的d
)。允许匹配从我们离开的地方继续。 - 尝试匹配第二个预测。在位置4处的
b
与p
不匹配,并且由于这是负向前视,所以我们想要;允许匹配继续。 - 尝试匹配
\w
的第4位。b
比赛。由于我们已经消耗了一个字符并继续,因此前进光标同样将此标记为比赛的开始。
- 尝试在第一回顾后在位置3
- 文本光标位置:5.
- 尝试匹配在第4位的第二回顾后(因为
q
总是匹配1个字符)。d
不符合q
这是我们想要从负面看后面。 - 意识到我们处于正则表达式的末尾,并通过将匹配字符串从当前位置(4到5)返回到
d
来报告成功。
- 尝试匹配在第4位的第二回顾后(因为
'[^]&[^]'可能比'。&。(?<!&)'更容易理解。 – Gumbo 2010-01-24 09:30:12
这将不会匹配“this&that”,而lookbehind版本会。一个有效的等价物应该是:'\ S&|&\ S' – 2010-01-24 09:47:09