Perl 非贪婪匹配——是“?”字符使用正确吗?
Perl Non-greedy Matching -- Is the "?" character used correctly?
我正在尝试匹配参数声明行的参数名称,如下所示:
parameter BWIDTH = 32;
使用的 Perl 正则表达式是:
$line =~ /(\w+)\s*=/
其中参数名称 BWIDTH
被捕获到 </code>。我遇到的大多数参数都是这样声明的,即名称前面有等号 <code>"="
,这就是正则表达式设计为其中包含 "="
(/(\w+)\s*=/
) 的原因。
但是也有声明参数的特殊情况:
parameter reg [31:0] PORT_WIDTH [BWIDTH-1:0] = 32;
在这种情况下,我要捕获的参数名称是 PORT_WIDTH
。修改正则表达式以匹配此实例不会成功捕获 PORT_WIDTH
,尽管它确实可以捕获 BWIDTH
。
$line =~ /(\w+)(\s*\[.*?\])*\s*=/
其中(\s*\[.*?\])*
匹配reg [31:0] PORT_WIDTH [BWIDTH-1:0]
,这是贪心匹配。
我很困惑为什么元字符 ?
不停止贪婪匹配?我该如何修改正则表达式?
将 .*?
替换为 [^][]*
以匹配 ]
和 [
以外的 0+ 个字符:
/(\w+)(\s*\[[^][]*])*\s*=/
^^^^^^
如果您不使用该值,您也可以将第二个捕获组变为非捕获组。
图案详情:
(\w+)
- 第 1 组:一个或多个单词字符
(\s*\[[^][]*])*
- 捕获组(在 (
之后添加 ?:
以使其成为非捕获组)零次或多次出现:
\s*
- 0+ 个空格
\[
- 文字 [
[^][]*
- 否定字符 class 匹配 ]
和 [
以外的零个或多个字符
]
- 文字 ]
\s*
- 零个或多个空格
=
- 等号。
贪婪与非贪婪会影响匹配结束的位置,但它仍然会尽可能早地开始。基本上,贪婪匹配是最左边最长的可能匹配,而非贪婪匹配是最左边最短的匹配。但是非贪心还是最左的,不是最右的。
为了得到你想要的,我会使用更明确的描述来描述我想要匹配的内容:/(\w+)(\s*\[[^]]*\])?\s*=/
在英语中,这是一个单词 (\w+
),可以选择后跟一些正方形的文本括号 ((\s*\[[^]]*\])?
),然后是可选的空格和等号。请注意,我使用了否定字符 class ([^]]
) 而不是括号内的非贪婪匹配 - IMO,否定字符 classes 通常是比非-更好的选择贪心匹配。
使用此正则表达式的结果:
$ perl -E '$x = q(parameter reg [31:0] PORT_WIDTH [BWIDTH-1:0] = 32;); $x =~ /(\w+)(:?\s*\[[^]]*\])?\s*=/; say ;'
PORT_WIDTH
$ perl -E '$x = q(parameter BWIDTH = 32;); $x =~ /:?(\w+)(\s*\[[^]]*\])?\s*=/; say ;'
BWIDTH
您有可用的信息,但您选择不使用。您知道要解析的每个语句的基本结构。这些语句有强制性和可选部分。因此,将您拥有的信息放入比赛中。例如:
#!/usr/bin/env perl
use strict;
use warnings;
my $stuff_in_square_brackets = qr{ \[ [^\]]+ \] }x;
my $re = qr{
^
parameter \s+
(?: reg \s+)?
(?: $stuff_in_square_brackets \s+)?
(\w+) \s+
(?: $stuff_in_square_brackets \s+)?
= \s+
(\w+) ;
$
}x;
while (my $line = <DATA>) {
if (my($p, $v) = ($line =~ $re)) {
print "'$p' = '$v'\n";
}
}
__DATA__
parameter BWIDTH = 32;
parameter reg [31:0] PORT_WIDTH [BWIDTH-1:0] = 32;
输出:
'BWIDTH' = '32'
'PORT_WIDTH' = '32'
我正在尝试匹配参数声明行的参数名称,如下所示:
parameter BWIDTH = 32;
使用的 Perl 正则表达式是:
$line =~ /(\w+)\s*=/
其中参数名称 BWIDTH
被捕获到 </code>。我遇到的大多数参数都是这样声明的,即名称前面有等号 <code>"="
,这就是正则表达式设计为其中包含 "="
(/(\w+)\s*=/
) 的原因。
但是也有声明参数的特殊情况:
parameter reg [31:0] PORT_WIDTH [BWIDTH-1:0] = 32;
在这种情况下,我要捕获的参数名称是 PORT_WIDTH
。修改正则表达式以匹配此实例不会成功捕获 PORT_WIDTH
,尽管它确实可以捕获 BWIDTH
。
$line =~ /(\w+)(\s*\[.*?\])*\s*=/
其中(\s*\[.*?\])*
匹配reg [31:0] PORT_WIDTH [BWIDTH-1:0]
,这是贪心匹配。
我很困惑为什么元字符 ?
不停止贪婪匹配?我该如何修改正则表达式?
将 .*?
替换为 [^][]*
以匹配 ]
和 [
以外的 0+ 个字符:
/(\w+)(\s*\[[^][]*])*\s*=/
^^^^^^
如果您不使用该值,您也可以将第二个捕获组变为非捕获组。
图案详情:
(\w+)
- 第 1 组:一个或多个单词字符(\s*\[[^][]*])*
- 捕获组(在(
之后添加?:
以使其成为非捕获组)零次或多次出现:\s*
- 0+ 个空格\[
- 文字[
[^][]*
- 否定字符 class 匹配]
和[
以外的零个或多个字符
]
- 文字]
\s*
- 零个或多个空格=
- 等号。
贪婪与非贪婪会影响匹配结束的位置,但它仍然会尽可能早地开始。基本上,贪婪匹配是最左边最长的可能匹配,而非贪婪匹配是最左边最短的匹配。但是非贪心还是最左的,不是最右的。
为了得到你想要的,我会使用更明确的描述来描述我想要匹配的内容:/(\w+)(\s*\[[^]]*\])?\s*=/
在英语中,这是一个单词 (\w+
),可以选择后跟一些正方形的文本括号 ((\s*\[[^]]*\])?
),然后是可选的空格和等号。请注意,我使用了否定字符 class ([^]]
) 而不是括号内的非贪婪匹配 - IMO,否定字符 classes 通常是比非-更好的选择贪心匹配。
使用此正则表达式的结果:
$ perl -E '$x = q(parameter reg [31:0] PORT_WIDTH [BWIDTH-1:0] = 32;); $x =~ /(\w+)(:?\s*\[[^]]*\])?\s*=/; say ;'
PORT_WIDTH
$ perl -E '$x = q(parameter BWIDTH = 32;); $x =~ /:?(\w+)(\s*\[[^]]*\])?\s*=/; say ;'
BWIDTH
您有可用的信息,但您选择不使用。您知道要解析的每个语句的基本结构。这些语句有强制性和可选部分。因此,将您拥有的信息放入比赛中。例如:
#!/usr/bin/env perl
use strict;
use warnings;
my $stuff_in_square_brackets = qr{ \[ [^\]]+ \] }x;
my $re = qr{
^
parameter \s+
(?: reg \s+)?
(?: $stuff_in_square_brackets \s+)?
(\w+) \s+
(?: $stuff_in_square_brackets \s+)?
= \s+
(\w+) ;
$
}x;
while (my $line = <DATA>) {
if (my($p, $v) = ($line =~ $re)) {
print "'$p' = '$v'\n";
}
}
__DATA__
parameter BWIDTH = 32;
parameter reg [31:0] PORT_WIDTH [BWIDTH-1:0] = 32;
输出:
'BWIDTH' = '32'
'PORT_WIDTH' = '32'