使用一个正则表达式

时间:2016-06-10 10:27:45

标签: php regex regex-negation regex-lookarounds

我需要一个匹配特定捕获组的正则表达式,该捕获组属于多行注释/ * ... * /。

特别是我需要在多行注释中找到PHP变量定义

例如:

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

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

必须只匹配评论中的两个'$ var =',而不是评论之外的那个。

对于上面的例子我写了一个使用无限制lookbehind的正则表达式,比如这个

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

但是这个正则表达式失败,以防它找到charachter *和/即使它们是APART彼此之间,在注释开始标记'/ *'和$ var之间,这不是所需的行为:

例如它在这种情况下失败:

$var = .... ;

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

因为它找不到'*'和'/',即使它不是评论结束标记。

关键是我不能否定一个两个字符组合的标记,但只能一个一个地否定它们:[^ *]或[^ /]。

...此外,我不能使用令牌[\ s \ S]而不是[^ /]和[^ *],因为它会选择$ var,而不是前面的评论块。

有什么想法吗?是否可以通过正常的正则表达式实现这一目标?或者我需要不同的东西吗?

4 个答案:

答案 0 :(得分:2)

这只与$var匹配,并且只在多行注释中匹配:

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

DEMO

(?:(?!/\*|\*/).)*是一个俘虏前瞻(也称为Tempered Greedy Token - 好名字,但音节太多),它是如何排除序列的,而不是单个字符。只要它不是(?s)/*的第一个字符,就会匹配任何字符的零个或多个(包括换行符,因为*/)。

如果在没有遇到*/的情况下找到/*,则封闭式前瞻会成功。这意味着当前位置必须在评论内(没有必要匹配开头/*)。并且因为前瞻不会消耗任何字符,所以如果需要,您可以为每条评论匹配多个项目。

可以欺骗这个正则表达式的一件事是*/并不是真正的评论。所以这些:

$var = "*/";

$var = ...;
// */

......即使他们不在评论中也会匹配。

答案 1 :(得分:1)

怎么样:

$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";
)

答案 2 :(得分:1)

使用\G to glue匹配/*

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

如果你没有用正则表达式做很多事情,可能很难理解。 See regex101 for demo

\G可以被视为&#34; glue&#34;,它会在上一场比赛结束时继续。但是\G也匹配字符串的开头。这就是为什么使用负前瞻\G(?!^)只需继续。

  • /\*|\G(?!^)此部分用于在/*找到匹配的开头或继续匹配。

  • (?:(?!\*/)[^$])*匹配任何不是$(否定类)的字符数,而不是(?!\*/)之前/之间的内容$var。 p>

  • \K\$var \K resets$var发生之前报告的匹配开始。 \K可用作替代pcre中不可用的可变宽度lookebhind。

  • \s*=\s*(?:(?!\*/)[^$;])*以匹配变量的值。这远非完美。如果quoted values或者不方便您输入,则需要修改。在=之后,它与[^$;]个字符匹配,这不是美元或分号(?!\*/)只要前面没有*/

此正则表达式不会检查是否实际存在评论结束*/它只是将匹配项绑定到/*
另一个想法是使用this trick种动词(*SKIP)(*FAIL),如in this demo

答案 3 :(得分:0)

这样的事可能有用:

/\/\*.*?\$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]

Try it online