Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/296.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 用一个正则表达式在多行注释中查找单词_Php_Regex_Regex Negation_Regex Lookarounds - Fatal编程技术网

Php 用一个正则表达式在多行注释中查找单词

Php 用一个正则表达式在多行注释中查找单词,php,regex,regex-negation,regex-lookarounds,Php,Regex,Regex Negation,Regex Lookarounds,我需要一个正则表达式,该正则表达式匹配多行注释内的特定捕获组/*…*/ 特别是,我需要在多行注释中找到PHP变量定义 例如: /* other code $var = value1 */ $var = value2 ; /* other code $var = value3 ; other code */ 必须仅匹配注释内出现的两个“$var=”项,而不匹配注释外出现的一个 对于上面的示例,我编写了一个使用无限制lookback的正则表达式,如下所示 (?<=[/][\*][^/]+

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

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

例如:

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

/* 
other code
$var = value3 ;
other code
*/
必须仅匹配注释内出现的两个“$var=”项,而不匹配注释外出现的一个

对于上面的示例,我编写了一个使用无限制lookback的正则表达式,如下所示

(?<=[/][\*][^/]+)(\$var) | (?<=[/][\*][^\*]+)(\$var)
因为它可以同时找到“*”和“/”,即使它不是注释结束标记

关键的一点是,我不能否定由两个字符组合而成的标记,而只能逐个否定它们:[^*]或[^/]

…此外,我不能使用标记[\s\s]而不是[^/]和[^*],因为它会从前面的注释块前面的注释中选择$var


有什么想法吗?使用普通正则表达式是否有可能实现这一点?或者我需要一些不同的东西吗?

像这样的东西可能有用:

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

那么:

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

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

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

(?:(?!/\*\\*\*/)*
是一种强制的前瞻(也称为一个好名字,但音节太多),它是排除序列而不是单个字符的方式。只要不是
/*
*/
的第一个字符,该字符就可以匹配任何字符中的零个或多个字符(包括换行符,因为
(?s)

如果在未首先遇到
/*
的情况下找到
*/
,则封闭的先行查找将成功。这意味着当前位置必须在注释中(无需匹配开头的
/*
)。由于前瞻不使用任何字符,如果需要,您可以在每条注释中匹配多个项目

有一件事可以愚弄这个正则表达式,那就是
*/
,它并不是真正的注释。因此,这些:

$var = "*/";

$var = ...;
// */
。。。将匹配,即使它们不在注释中。

使用匹配到
/*

(?:/\*|\G(?!^))(?:(?!\*/)[^$])*\K\$var\s*=\s*(?:(?!\*/)[^$;])*
如果你不经常使用正则表达式,可能很难理解

\G
可以看作是“胶水”,它在上一场比赛结束时继续进行。但是
\G
也匹配字符串的开头。这就是为什么使用负前瞻
\G(?!^)
只需继续

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

  • (?:(?!\*/)[^$])*
    匹配任何数量的非
    $
    (否定类)字符,同时不结束注释
    (?!\*/)
    之前/之间的
    $var

  • \K\$var
    在发生
    $var
    之前报告的匹配开始<代码>\K可以用作pcre中不可用的可变宽度lookebhind的替代品

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

此正则表达式不检查是否确实存在注释结尾
*/
,它只是将匹配项绑定到
/*


另一个想法是使用类似动词的类型。

谢谢,但不幸的是,你的解决方案也匹配评论,而且似乎不考虑前一个注释块的情况。@ ObOMAR匹配在匹配组中被捕获<代码> 1代码>未<代码> 0 <代码>:<代码> $匹配(1)< /代码>右,在我提供的示例中,您的解决方案在概念上确实起作用,但它并不完整(对此表示抱歉)。我更新了这个问题,把这个例子变成了一个更一般的场景,其中有一行多行注释:考虑/*/$var /代码…变量..代码..*/它还能用吗?它似乎也会匹配$var外部评论。使用如何。谢谢!这个正则表达式回答了这个问题。使用meta字符\G效果很好!唯一的问题是对于初学者来说这有点难理解。。。我理解为什么在这种情况下使用它,但我仍然不能完全理解(?!^)的一般含义,因为它很有帮助。我给出了一个带解释的答案。消极的前瞻只是
(?!
,而不是
(?!=
。此外,封闭组一次只能使用一个字符。事实上,您的正则表达式只是偶然工作的。您的解决方案与您提供的示例相同,但在类似于@AlanMoore@Obomar:是的,在某些情况下它会失败。如果你想通过每一个案例,你必须o编写一个解析器。你是对的,除了你提到的和案例之外,你的正则表达式工作正常,我还想添加另一个案例:它与/*$var/*代码中的$var不匹配…*/…我相信我们可以想出更多的方法让它失败。正如@Toto在其他地方说的,要做到这一点,你需要一个实际的解析器。事实上,如果我认为你需要的话为了匹配分配给
$var
的值,我甚至没有尝试过。感谢@Alanmore的回答,从我的角度来看,你的正则表达式是最优雅、最容易理解的,但不幸的是,我需要管理在可能的开头分隔符之间匹配字符串的情况,否则我会使用你的正则表达式。我应该提到很抱歉。幸运的是,就这个问题而言,我不需要解析器来检查引号分隔符或管理嵌套注释(并将其视为嵌套注释),因为在我的情况下,引号分隔符不存在或非常罕见,只需要复制您在programmi中遇到的最常见的多行注释行为
$var = "*/";

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