PHP 确实支持前瞻表达式。不过,您可能没有正确使用它们。
假设您要匹配包含所有三个的字符串foo
, bar
and baz
,你需要正则表达式
^(?=.*foo)(?=.*bar)(?=.*baz)
这将返回字符串的匹配项foobarbaz
or barbazfoo
等等。但是,该匹配将是空字符串(因为先行查找不消耗任何字符)。如果您希望正则表达式返回字符串本身,请使用
^(?=.*foo)(?=.*bar)(?=.*baz).*
如果满足所有三个条件,它将匹配整个字符串。
我会简单地使用
if (preg_match('/^(?=.*foo)(?=.*bar)(?=.*baz)/s', $subject)) {
# Successful match
} else {
# Match attempt failed
}
请注意,这也会匹配类似的字符串foonly bartender bazooka
。如果您不希望这样做(只允许三个表达式中的每一个的纯排列),您可以用一个小技巧来做到这一点:
^(?:foo()|bar()|baz()){3}\1\2\3$
matches foobarbaz
, foobazbar
, barfoobaz
, barbazfoo
, bazfoobar
and bazbarfoo
(没有别的)。这个“把戏”的灵感来自 Jan Goyvaerts 和 Steven Levithan 的优秀著作《正则表达式食谱》 http://shop.oreilly.com/product/9780596520694.do(第 304 页)。其工作原理如下:
- 每个必需的部分(
foo
等)后面是一个空的捕获组()
如果所需部分已匹配,则始终匹配。
- 因此,如果所有三个必需部分都匹配,则所有三个空捕获组都匹配。
- 仅当每个捕获组都参与了匹配时,以下反向引用才会成功。
- 所以如果字符串是
foobarbar
, 那个部分(?:foo()|bar()|baz()){3}
将会匹配,但是\3
失败,因此整个正则表达式失败。
- 然而,如果三人都参加了比赛,
\1\2\3
成功匹配字符串末尾,因为每个捕获组只包含空字符串。