使用一个正则表达式在多行注释中查找单词
Find a word in multiline comment with one regex
我需要一个正则表达式来匹配位于多行注释 /* ... */ 中的特定捕获组。
特别是我需要在多行注释中找到 PHP 变量定义
例如:
/* other code $var = value1 */
$var = value2 ;
/*
other code
$var = value3 ;
other code
*/
必须只匹配注释中出现的两次“$var =”,而不匹配注释外的一次。
对于上面的例子,我写了一个正则表达式,它使用不受限制的回顾,就像这样
(?<=[/][\*][^/]+)($var) | (?<=[/][\*][^\*]+)($var)
但是这个正则表达式会失败,以防它在注释开始标记“/*”和 $var 之间找到字符 * 和 /,即使它们彼此分开,这不是所需的行为:
例如在以下情况下失败:
$var = .... ;
/*
other * code /
$var = .... ;
other code
*/
因为即使它不是评论结束标记,它也会找到“*”和“/”。
关键是我不能对两个字符组合的token取反,只能一个一个取反:[^*]或[^/]。
...此外,我不能使用令牌 [\s\S] 代替 [^/] 和 [^*],因为它会 select $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]);
输出:
Array
(
[0] => $var = "var2";
[1] => $var = "var4";
)
这只匹配 $var
,并且只在多行注释中:
(?s)$var(?=(?:(?!/\*|\*/).)*\*/)
(?:(?!/\*|\*/).)*
是一种强制性前瞻(也称为 Tempered Greedy Token——好名字,但音节太多),这是排除序列而不是单个字符的方式。这个匹配零个或多个任何字符(包括换行符,因为 (?s)
),只要它不是 /*
或 */
的第一个字符。
如果在没有首先遇到 /*
的情况下找到 */
,则封闭前瞻会成功。这意味着当前位置必须在评论内(不需要匹配开头 /*
)。由于前瞻不消耗任何字符,因此如果需要,您可以在每个评论中匹配多个项目。
可以骗过这个正则表达式的是 */
这不是真正的注释。所以这些:
$var = "*/";
$var = ...;
// */
...会匹配,即使他们不在评论中。
使用 \G to glue 的想法与 /*
匹配
(?:/\*|\G(?!^))(?:(?!\*/)[^$])*\K$var\s*=\s*(?:(?!\*/)[^$;])*
如果您不经常使用正则表达式,可能很难理解。 See regex101 for demo.
\G
可以看作是"glue",它在上一场比赛结束时继续。但是 \G
也匹配字符串的开头。这就是为什么使用负前瞻\G(?!^)
只需要继续。
/\*|\G(?!^)
这部分是在/*
找到一个匹配的开始或者继续匹配。
(?:(?!\*/)[^$])*
匹配任意数量的不是 $
的字符(取反 class),同时不结束对 stuff [=] 的注释 (?!\*/)
66=]$var
\K$var
\K
resets 在 $var
发生之前报告的匹配开始。 \K
可用作 pcre 中不可用的可变宽度 lookebhind 的替代方法。
\s*=\s*(?:(?!\*/)[^$;])*
来匹配变量的值。这远非完美。如果 quoted values 或不方便您输入,则需要修改。在 =
之后它匹配 [^$;]
个字符,这些字符不是美元或分号 (?!\*/)
只要前面没有 */
。
这个正则表达式不检查是否真的有注释结束 */
它只是将匹配项绑定到 /*
另一个想法是使用 this trick with verbs (*SKIP)(*FAIL)
like in this demo.
尝试 php,但 java 有效
(?s)(?i)(^|\s+?)(/*)((.)(?!*/))?(这)(.?)(*/)
in this example finding word is "this"
我需要一个正则表达式来匹配位于多行注释 /* ... */ 中的特定捕获组。
特别是我需要在多行注释中找到 PHP 变量定义
例如:
/* other code $var = value1 */
$var = value2 ;
/*
other code
$var = value3 ;
other code
*/
必须只匹配注释中出现的两次“$var =”,而不匹配注释外的一次。
对于上面的例子,我写了一个正则表达式,它使用不受限制的回顾,就像这样
(?<=[/][\*][^/]+)($var) | (?<=[/][\*][^\*]+)($var)
但是这个正则表达式会失败,以防它在注释开始标记“/*”和 $var 之间找到字符 * 和 /,即使它们彼此分开,这不是所需的行为:
例如在以下情况下失败:
$var = .... ;
/*
other * code /
$var = .... ;
other code
*/
因为即使它不是评论结束标记,它也会找到“*”和“/”。
关键是我不能对两个字符组合的token取反,只能一个一个取反:[^*]或[^/]。
...此外,我不能使用令牌 [\s\S] 代替 [^/] 和 [^*],因为它会 select $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]);
输出:
Array
(
[0] => $var = "var2";
[1] => $var = "var4";
)
这只匹配 $var
,并且只在多行注释中:
(?s)$var(?=(?:(?!/\*|\*/).)*\*/)
(?:(?!/\*|\*/).)*
是一种强制性前瞻(也称为 Tempered Greedy Token——好名字,但音节太多),这是排除序列而不是单个字符的方式。这个匹配零个或多个任何字符(包括换行符,因为 (?s)
),只要它不是 /*
或 */
的第一个字符。
如果在没有首先遇到 /*
的情况下找到 */
,则封闭前瞻会成功。这意味着当前位置必须在评论内(不需要匹配开头 /*
)。由于前瞻不消耗任何字符,因此如果需要,您可以在每个评论中匹配多个项目。
可以骗过这个正则表达式的是 */
这不是真正的注释。所以这些:
$var = "*/";
$var = ...;
// */
...会匹配,即使他们不在评论中。
使用 \G to glue 的想法与 /*
(?:/\*|\G(?!^))(?:(?!\*/)[^$])*\K$var\s*=\s*(?:(?!\*/)[^$;])*
如果您不经常使用正则表达式,可能很难理解。 See regex101 for demo.
\G
可以看作是"glue",它在上一场比赛结束时继续。但是 \G
也匹配字符串的开头。这就是为什么使用负前瞻\G(?!^)
只需要继续。
/\*|\G(?!^)
这部分是在/*
找到一个匹配的开始或者继续匹配。(?:(?!\*/)[^$])*
匹配任意数量的不是$
的字符(取反 class),同时不结束对 stuff [=] 的注释(?!\*/)
66=]$var
\K$var
\K
resets 在$var
发生之前报告的匹配开始。\K
可用作 pcre 中不可用的可变宽度 lookebhind 的替代方法。\s*=\s*(?:(?!\*/)[^$;])*
来匹配变量的值。这远非完美。如果 quoted values 或不方便您输入,则需要修改。在=
之后它匹配[^$;]
个字符,这些字符不是美元或分号(?!\*/)
只要前面没有*/
。
这个正则表达式不检查是否真的有注释结束 */
它只是将匹配项绑定到 /*
另一个想法是使用 this trick with verbs (*SKIP)(*FAIL)
like in this demo.
尝试 php,但 java 有效
(?s)(?i)(^|\s+?)(/*)((.)(?!*/))?(这)(.?)(*/)
in this example finding word is "this"