正则表达式查找父::

时间:2011-08-16 15:52:14

标签: php regex preg-match

我想找到所有出现的parent ::,被调用的函数和参数

例如:

parent::test( new ReflectionClass($this) );

但是下面的正则表达式与外部括号不匹配 - 只有内部括号:

parent::(.*)\((.*)\);
Array /* output */
(
    [0] => parent::test( new ReflectionClass($this) );
    [1] => test( new ReflectionClass
    [2] => $this) 
)

我如何修改模式?

这是一个PHP脚本,所以我也可以使用其他一些字符串函数。

4 个答案:

答案 0 :(得分:2)

正常表达式通常无法实现您的目标。要做你想做的事,你必须能够计算事物,这是正则表达式无法做到的事情。

使匹配贪婪最终会导致匹配太多,尤其是当您支持多行输入时。

要替换父类的每个出现::你可能不必完全匹配方法调用,也许它足以匹配这样的东西:

parent::(.*);

然后你可以用其他东西替换parent ::并使用第一个匹配组来放置文档中此处的任何内容。

答案 1 :(得分:2)

使用正则表达式来解析代码是一个非常糟糕的主意。查看PHP's Tokenizer,您可以使用它将PHP代码解析为令牌数组。您可以使用该数组来查找所需的信息。

您还可以查看PHP-Token-Reflection's source code作为如何从这些令牌中获取有意义信息的示例。

基本上,您需要找到 T_PARENT出现 T_STRING出现,其中'parent'作为字符串内容,然后是T_DOUBLE_COLON,接着是另一个包含方法名称的T_STRING,而不是前进并开始计数括号的深度 - 每当你得到一个'(',将计数器增加一个。每当你得到一个')'时,将计数器减一。记录您在流程中找到的所有内容,直到计数器返回到0。

这样的事情应该有效(没有经过实际测试):

<?php
$tokens = tokens_get_all(...);
for ($i=0, $size = count($tokens); $i < $size; $i++( {
    if ($tokens[$i][0] === T_STRING && $tokens[$i][1] === 'parent' && $tokens[++$i][0] === T_DOUBLE_COLON && $tokens[++$i][0] === T_STRING) {
        $method = $tokens[$i][1];
        $depth = 0;
        $contents = array();
        do {
            $contents[] = $token = $tokens[++$i];
            if ($token === '(') {
                $depth++;
            } elseif ($token === ')') {
                $depth--;
            }
        } while ($depth > 0);
        echo "Call to $method with contents:\n";
        print_r(array_slice($contents, 1, -1)); // slices off the opening '(' and closing ')'
    }
}

答案 2 :(得分:1)

这是一个不太健壮的例子,但它会与你问题中的情况相符。

(parent::)([^\(]*)\(([^\(]*)\(([^()]*)\)

这是一个实时的正则表达式测试来试验:http://rubular.com/r/WwRsRTf7E6(注意:rubular.com针对ruby,但应该与php相似)。

匹配的元素就是这种情况:

parent::
test
new ReflectionClass
$this

如果你想要更强大的东西,你可能想要研究解析工具(例如,写一个匹配php函数定义的短语法)或静态代码分析工具,因为它们通常由AST生成器等组成。我没有个人有这个经验,但听起来相当全面:

  

pfff是一组工具和API,用于执行一些静态分析,动态   分析,代码可视化,代码导航或样式保留   源到源的转换,例如源代码的重构。   目前,这项工作主要集中在PHP ......

答案 3 :(得分:1)

如果您只对该功能以及圆括号内的任何内容感兴趣,请执行 并且大多数parent ::调用仅在一行中。这可能适合你。

parent::(.*?)\((.*)\);

第一次捕获应该在第一次遇到(后停止,因为这不是贪心 第二次捕获将不会停止,直到它捕获同一行上的最后一个);

注意:请勿使用s修饰符,因为这会导致与代码的多行中的最后);进行贪婪匹配。