为什么preg_match匹配最后一个子模式而不是第一个?

时间:2012-01-06 23:11:21

标签: php regex

我试图匹配可以包含许多十六进制地址的行中的第一个十六进制地址,但是我得到了最后一个。

我的要求是:

preg_match('%.*(0x[0-9a-f]{8}){1}.*%', $v, $current_match);

其中$v是一个字符串,如:

Line: 2 libdispatch.dylib 0x36eaed55 0x36eae000 + 3413

我希望获得0x36eaed55,但$current_match[1]的正则表达式会返回0x36eae000

根据php文档: $matches[1]将具有与第一个捕获的带括号的子模式匹配的文本,依此类推。

4 个答案:

答案 0 :(得分:4)

第一个.*尝试尽可能匹配,因此它也匹配您的第一个十六进制。试着让它不贪心:.*?

答案 1 :(得分:4)

那是因为你的第一个.*是贪婪的。您可以通过将正则表达式更改为:

来解决此问题
preg_match('%(0x[0-9a-f]{8})%', $v, $current_match);

preg_match('%.*?(0x[0-9a-f]{8})%', $v, $current_match);

答案 2 :(得分:3)

问题是默认情况下*量词是贪婪的,所以第一个.*尽可能匹配,同时仍允许整个表达式匹配。在这种情况下,这意味着.*将“吞噬”所有十六进制常量,但最后一个,因为(0x[0-9a-f]{8}){1}仍然需要匹配。

一种解决方案是使用非贪婪的运算符*?。使用以下内容时会找到第一个常量:

preg_match('%.*?(0x[0-9a-f]{8}){1}.*?%', $v, $current_match);

但是,因为您知道$v包含一个十六进制常量,并且您想要第一个,那么为什么不简单地匹配十六进制常量的模式?

preg_match('%0x[0-9a-f]{8}%', $v, $current_match);

即使您想要第二个,第三个,第四个,......十六进制常量,也可以使用相同模式的preg_match_all()

preg_match_all('%0x[0-9a-f]{8}%', $v, $all_matches, PREG_PATTERN_ORDER);

答案 3 :(得分:1)

您需要使用ungreedy修饰符“U”:

preg_match('%.*(0x[0-9a-f]{8}){1}.*%U', $v, $m);