Perl非贪心匹配 - 是“?”正确使用了哪个字符?

时间:2017-06-19 08:41:48

标签: regex perl greedy regex-greedy

我正在尝试匹配参数声明行的参数名称,如下所示:

parameter BWIDTH = 32;

使用的Perl正则表达式是:

$line =~ /(\w+)\s*=/

其中参数名称BWIDTH被捕获到$1中。我遇到的大多数参数都是以这样的方式声明的,即名称在等号"="之前,这就是正则表达式设计中包含"="/(\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]

我很困惑为什么元字符?不会停止贪婪的匹配?我该如何修改正则表达式?

3 个答案:

答案 0 :(得分:2)

.*?替换为[^][]*,以匹配][以外的0 +字符:

/(\w+)(\s*\[[^][]*])*\s*=/
            ^^^^^^

如果您没有使用该值,您也可以将第二个捕获组变为非捕获组。

模式详情

  • (\w+) - 第1组:一个或多个单词字符
  • (\s*\[[^][]*])* - 一个捕获组(在?:之后添加(以使其无法捕获)零次或多次出现:
    • \s* - 0+ whitespaces
    • \[ - 文字[
    • [^][]* - 与][以外的零个或多个字符匹配的否定字符类
    • ] - 文字]
  • \s* - 零个或多个空格
  • = - 等号。

答案 1 :(得分:2)

贪婪与非贪婪会影响匹配结束的位置,但仍会尽早启动。基本上,贪婪的匹配是最左边最长的匹配,而非贪婪是最左边的。但非贪婪仍然是最左边的,而不是最右边的。

为了得到你想要的东西,我会更明确地描述我想要匹配的东西:/(\w+)(\s*\[[^]]*\])?\s*=/在英语中,这是一个单词(\w+),可选地后跟一些文字方括号((\s*\[[^]]*\])?),然后是可选的空格和等号。请注意,我使用了一个否定的字符类([^]])而不是非贪婪的匹配括号内的内容 - IMO,否定的字符类通常比非贪婪的匹配更好。

此正则表达式的结果:

$ perl -E '$x = q(parameter reg [31:0] PORT_WIDTH [BWIDTH-1:0] = 32;); $x =~ /(\w+)(:?\s*\[[^]]*\])?\s*=/; say $1;'
PORT_WIDTH
$ perl -E '$x = q(parameter BWIDTH = 32;); $x =~ /:?(\w+)(\s*\[[^]]*\])?\s*=/; say $1;'
BWIDTH

答案 2 :(得分:1)

您可以选择不使用的信息。您知道要尝试解析的每个语句的基本结构。这些陈述有强制性和可选部分。所以,把你的信息放到比赛中。例如:

#!/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'