Регулярное выражение для поиска родителя :: - PullRequest
0 голосов
/ 16 августа 2011

Я хочу найти все вхождения parent ::, вызываемой функции и параметра

Например:

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

Но следующее регулярное выражение не соответствует внешним скобкам - только внутренним:

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

Как мне изменить шаблон?

Это для сценария PHP, поэтому я могу использовать и некоторые другие строковые функции.

Ответы [ 4 ]

2 голосов
/ 16 августа 2011

Использование регулярных выражений для разбора кода - ДЕЙСТВИТЕЛЬНО плохая идея. Взгляните на Tokenizer PHP , который вы можете использовать для разбора PHP-кода в массив токенов. Вы можете использовать этот массив, чтобы найти нужную информацию.

Вы также можете посмотреть исходный код PHP-Token-Reflection как пример того, как получить значимую информацию из этих токенов.

Как правило, вам нужно будет найти вхождений 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 голосов
/ 16 августа 2011

То, что вы пытаетесь сделать, обычно невозможно с регулярными выражениями. Чтобы делать то, что вы хотите, вы должны иметь возможность считать вещи, чего не могут делать регулярные выражения.

Жадность сопоставления в конечном итоге приведет к слишком сильному сопоставлению, особенно если вы поддерживаете многострочный ввод.

Чтобы заменить каждое вхождение parent :: вам, вероятно, не обязательно точно совпадать с вызовом метода, может быть, этого достаточно, чтобы сопоставить что-то вроде этого:

parent::(.*);

Затем вы можете заменить parent :: чем-то другим и использовать первую подходящую группу, чтобы поместить все, что было в документе, в эту позицию.

1 голос
/ 16 августа 2011

Если вас интересует только функция и все, что находится внутри круглых скобок,и большинство parent :: call находятся только в одной строке.Это может работать для вас.

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

Первый захват должен прекратиться после первого обнаруженного (, так как это не жадно.Второй захват не остановится, пока он не захватит последний ); в той же строке.

Примечание: не используйте модификатор s, так как это приведет к жадному совпадению до последнего ); в несколькихстроки вашего кода.

1 голос
/ 16 августа 2011

Вот пример, который на самом деле не является надежным, но он соответствовал бы регистру в вашем вопросе.

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

Вот живой тест регулярного выражения, чтобы поэкспериментировать: http://rubular.com/r/WwRsRTf7E6 (Примечание: rubular.com нацелен на ruby, но должен быть достаточно похож на php).

Соответствующие элементы будут в этом случае:

parent::
test
new ReflectionClass
$this

Если вы хотите что-то более надежное, выВозможно, вы захотите изучить инструменты синтаксического анализа (например, написать короткую грамматику, которая соответствует определениям функций php) или инструменты статического анализа кода, так как они часто состоят из генераторов AST и т. д. У меня нет личного опыта с этим, но это звучит довольно всесторонне:

pfff - это набор инструментов и API для выполнения статического анализа, динамического анализа, визуализации кода, навигации по коду или стиля.сохранение преобразований исходного кода, таких как рефакторинг исходного кода.На данный момент усилия сосредоточены на PHP ...

...