tjw*_*992 4 regex perl regex-recursion
我正在尝试编写一个递归正则表达式来捕获代码块,但由于某种原因它似乎没有正确捕获它们.我希望下面的代码能够捕获函数的完整主体,但它只捕获第一个if语句的内容.
它几乎就像.+?是以某种方式吞噬了第一个{,但它应该是非贪婪的,所以我不明白它为什么会这样.
是什么导致它以这种方式行事?
脚本:
use strict;
use warnings;
my $text = << "END";
int max(int x, int y)
{
if (x > y)
{
return x;
}
else
{
return y;
}
}
END
# Regular expression to capture balanced "{}" groups
my $regex = qr/
\{ # Match opening brace
(?: # Start non-capturing group
[^{}]++ # Match non-brace characters without backtracking
| # or
(?R) # Recursively match the entire expression
)* # Match 0 or more times
\} # Match closing brace
/x;
# is ".+?" gobbling up the first "{"?
# What would cause it to do this?
if ($text =~ m/int\s.+?($regex)/s){
print $1;
}
Run Code Online (Sandbox Code Playgroud)
输出:
{
return x;
}
Run Code Online (Sandbox Code Playgroud)
预期产出:
{
if (x > y)
{
return x;
}
else
{
return y;
}
}
Run Code Online (Sandbox Code Playgroud)
我知道有一个Text::Balanced模块用于此目的,但我试图手动执行此操作以了解有关正则表达式的更多信息.
(?R)进入整个模式 - 但整个模式是什么?当您嵌入引述$regex到/int\s.+?($regex)/,该模式被重新编译,并(?R)指新格局.这不是你想要的.
我建议您使用命名捕获,以便您可以按名称递归.改变之$regex类的
/(?<nestedbrace> ... (?&nestedbrace) ...)/
Run Code Online (Sandbox Code Playgroud)
如果要避免额外捕获,可以使用(?(DEFINE) ...)语法声明可以在以后调用的命名正则表达式模式:
my $define_nestedbrace_re = qr/(?(DEFINE)
(?<nestedbrace ... (?&nestedbrace) ...)
)/x;
Run Code Online (Sandbox Code Playgroud)
然后: /int\s.+?((?&nestedbrace))$define_nestedbrace_re/
这不会产生额外的捕获.但是,通常不可能编写封装的正则表达式片段.喜欢命名捕获而不是编号捕获的技术可以在这里提供帮助.