使用后视或捕获组是否更好?

时间:2010-01-25 03:28:08

标签: php regex

我不确定其中一个是否比另一个“更好”,为什么会这样,但我有一个看起来像这样的原始字符串:

$string = '/random_length_user/file.php';

现在,有两种方法可以匹配它,第一种方式,使用我的新朋友,后视和第二种,没有:

preg_match("%(?<=^/)([^/]*)%", $string, $capture);
preg_match("%^/([^/]*)%", $string, $capture);

他们按顺序返回:

Array
(
    [0] => random_length_user
)
Array
(
    [0] => /random_length_user
    [1] => random_length_user
)

基本上我使用look-behind在$ capture [0]中获得我想要的结果,而在$ capture [1]中没有。现在问题是......是否有理由偏好这些方法中的一种而不是另一种?

2 个答案:

答案 0 :(得分:3)

它可能与preg_match无关,但在使用preg_replace时会很重要,因为它会影响要替换的内容。

当您进行全局匹配时,这也可能是一个问题,因为捕获组将消耗字符,而外观不会

琐碎的例子:

  • /(?<=a)a/g'aaaa'一致Array('a', 'a', 'a')
  • /(a)a/g'aaaa'一致Array('aa', 'aa')

答案 1 :(得分:1)

问题在于,后视方法并不灵活;当你开始处理可变长度匹配时,它就会崩溃。例如,假设您要在示例中提取文件名,并且您不知道目录的名称。捕获组技术仍然可以正常工作:

preg_match("%^/\w+/([^/]*)%", '/random_length_user/file.php');

Array
(
    [0] => /random_length_user/file.php
    [1] => file.php
)

...但是后视方法没有,因为lookbehind表达式只能匹配固定数量的字符。但是,有一个更好的选择:\K,MATCH POINT RESET运算符。无论你把它放在哪里,正则表达式引擎都假装比赛真的从那里开始。因此,您可以获得与使用lookbehind相同的结果,没有固定长度限制:

preg_match('%^/\w+/\K[^/]+$%', '/random_length_user/file.php');

Array
(
    [0] => file.php
)

据我所知,此功能仅适用于Perl 5.10+以及由PCRE库驱动的工具(如PHP的preg_函数)。有关PCRE参考,请参阅the manpage并搜索(F3)\K