Найти слово в многострочном комментарии с одним регулярным выражением

Мне нужно регулярное выражение, соответствующее определенной группе захвата, которая попадает в многострочный комментарий / * … * /.

В частности, мне нужно найти определения переменных PHP внутри многострочных комментариев

например:

/* other code $var = value1 */
$var = value2 ;

/*
other code
$var = value3 ;
other code
*/

должен соответствовать только двум вхождениям $ var = внутри комментариев, но не одному за пределами комментария.

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

(?<=[/][\*][^/]+)(\$var) | (?<=[/][\*][^\*]+)(\$var)

но это регулярное выражение не выполняется в случае, если он находит оба символа * и /, даже если они APART друг от друга, между открывающим тег комментарием ‘/ *’ и $ var, что не является желаемым поведением:

например, это терпит неудачу в случае:

$var = .... ;

/*
other * code /
$var = .... ;
other code
*/

потому что он находит ‘*’ и ‘/’, даже если это не закрывающий тег комментарий.

Ключевым моментом является то, что я не могу отменить токен, который является комбинацией двух символов, но могу отменить их только один за другим: [^ *] или [^ /].

…Более того, я не могу использовать токен [\ s \ S] вместо [^ /] и [^ *], потому что он выберет $ var из комментариев, которым предшествует предыдущий блок комментариев.

Есть идеи? Можно ли даже с помощью регулярных выражений достичь этого? Или мне нужно что-то другое?

3

Решение

Идея использования \ G клеить соответствует /*

(?:/\*|\G(?!^))(?:(?!\*/)[^$])*\K\$var\s*=\s*(?:(?!\*/)[^$;])*

Может быть трудно понять, если вы не много делаете с регулярными выражениями. Смотрите regex101 для демонстрации.

\G может рассматриваться как «клей», это продолжается в конце предыдущего матча. Но \G также соответствует началу строки. Вот почему используется негативный взгляд \G(?!^) нужно только продолжить.

  • /\*|\G(?!^) Эта часть, чтобы найти начало матча в /* или продолжить сопоставление.

  • (?:(?!\*/)[^$])* Подберите любое количество символов, которые не являются $ (отрицается класс), не заканчивая комментарий (?!\*/) для вещей до / между $var

  • \K\$var \K перезагружается начало указанного матча до $var происходит. \K может быть полезен в качестве альтернативы lookebhind переменной ширины, который не доступен в pcre.

  • \s*=\s*(?:(?!\*/)[^$;])* чтобы соответствовать значению переменной. Это далеко не идеально. Потребуется модификация, если приведенные значения или не удобно для вашего ввода. После = это соответствует [^$;] символы, которые не являются долларом или точкой с запятой (?!\*/) пока нет */ вперед.

Это регулярное выражение не проверяет, есть ли на самом деле конец комментария */ это просто связывает спички /*
Другой идеей было бы использовать вид этот трюк с глаголами (*SKIP)(*FAIL) лайк в этой демонстрации.

1

Другие решения

Это соответствует просто $varи только внутри многострочного комментария:

(?s)\$var(?=(?:(?!/\*|\*/).)*\*/)

DEMO

(?:(?!/\*|\*/).)* это плененный взгляд (также известный как Закаленный жадный жетон—хорошее имя, но слишком много слогов), и именно так вы исключаете последовательность, в отличие от одного символа. Этот соответствует нулю или более любого символа (включая символ новой строки, потому что (?s)), пока это не первый персонаж /* или же */,

Включающий lookahead преуспевает, если находит */ без первого знакомства /*, Это означает, что текущая позиция должна быть внутри комментария (нет необходимости совпадать с открытием /*). А так как предвидение не потребляет никаких символов, вы можете сопоставить более одного элемента на комментарий, если вам нужно.

Одна вещь, которая может обмануть это регулярное выражение */ это не совсем комментарий ближе. Итак, эти:

$var = "*/";

$var = ...;
// */

… будет соответствовать, даже если они не в комментарии.

2

Как насчет:

$str = '
/* other code */
$var = "var1";

/*
other code
$var = "var2";
other code
*/
/* other code */
$var = "var3";

/*
other code / <-- a slash here
$var = "var4";
other code
*/';

preg_match_all('~/\*(?:(?!\*/).)+?(\$var = .+?;).*?\*/~s', $str, $m);
print_r($m[1]);

Выход:

Array
(
[0] => $var = "var2";
[1] => $var = "var4";
)
1

Нечто подобное может работать:

/\/\*.*?\$var\s*\=\s(.*?)(?=\s*;)/s

Использование:

$str = '$var = .... ;
/*
other code
$var = ..... ;
other code
*/';
preg_match('/\/\*.*?\$var\s*\=\s(.*?)(?=\s*;)/s', $str, $matches);

var_dump($matches);

Будет выводить:

array(2) {
[0]=>
string(26) "/*
other code
$var = ....."[1]=>
string(5) "....."}

И ваша строка хранится в $matches[1]

Попробуйте онлайн

0
По вопросам рекламы [email protected]