如何让preg_match_all同时匹配重叠子串foot、ball及football?
如何让正则同时匹配重叠/包含的子串
你遇到的问题本质是正则引擎的默认“字符消耗”行为:当正则匹配到一段字符后,这些字符就会被标记为“已使用”,后续的匹配无法再复用它们。比如在"football"中,当引擎先匹配到"foot"后,剩下的字符只有"ball",此时"football"需要完整的8个字符,自然就匹配不到了——哪怕你调换了正则里的顺序,引擎还是会优先匹配先出现的模式,消耗掉对应字符后,长模式就没机会匹配了。
要解决这个问题,关键是让正则不消耗字符,同时检查所有可能的匹配。这里可以用正向先行断言(positive lookahead),它是零宽度匹配(不会移动引擎的匹配指针),只会检查当前位置之后是否存在目标模式,不会消耗任何字符。
解决方案代码
在PHP中,你可以这样写:
preg_match_all('/(?=(foot|ball|football))/', 'I like football', $results); print_r($results[1]);
这段代码的输出会是:
Array ( [0] => foot [1] => football [2] => ball )
原理说明
(?=...)是正向先行断言,它会检查当前位置之后是否能匹配括号内的模式,但不会消耗字符。- 我们把需要匹配的三个子串放在捕获组
(foot|ball|football)里,这样每一次预查匹配成功时,捕获组就会记录对应的子串。 - 正则引擎会逐个遍历字符串的每个位置,检查该位置之后是否存在任意一个目标子串,因此所有可能的匹配(包括重叠/包含的)都会被捕获到。
补充说明
如果你的需求只是确认哪些子串存在(而不是获取所有出现的位置),可以对结果去重:
$uniqueMatches = array_unique($results[1]); print_r($uniqueMatches);
这样就能得到['foot', 'football', 'ball']的去重结果。
内容的提问来源于stack exchange,提问作者Kristian
相关产品推荐
相关产品推荐

