Php 用一个正则表达式在多行注释中查找单词
我需要一个正则表达式,该正则表达式匹配多行注释内的特定捕获组/*…*/ 特别是,我需要在多行注释中找到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的正则表达式,如下所示 (?<=[/][\*][^/]+
/* 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
之前报告的匹配开始<代码>\K可以用作pcre中不可用的可变宽度lookebhind的替代品$var
以匹配变量的值。这远非完美。如果您的输入不方便,则需要修改。在\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*(?:(?!\*/)[^$;])*