【问题标题】:Why is Perl not printing all regex matches found in single line?为什么 Perl 不打印在单行中找到的所有正则表达式匹配?
【发布时间】:2019-01-25 21:29:26
【问题描述】:

我有一个正则表达式,它匹配文本文件中一行内的多个字符串。但是,当我使用它来尝试打印捕获组的所有实例时,它只打印第一个实例。

我的正则表达式是:

/"resolution.(\w+)/g

当将以下行提供给正则表达式时:

"signalcfg": "{\"signals\":[{\"order\":1,\"id\":\"oryx_C20C0E15-2028-4F4B-A8DD-0DA8D87B4FF9\",\"name\":\"success\",\"rrcodes\":\"resolution.COMPLAINTS_CHANGE_STATUS_SUCCESS\",\"testModule\":\"MCSChangeComplaintsStatus\",\"default\":false},{\"order\":2,\"id\":\"oryx_C943ADB8-6FA2-4DA1-B4D7-24515D96B9DA\",\"name\":\"TimeOut\",\"rrcodes\":\"resolution.MCS_CHANGE_COMPLAINTS_STATUS_TIMEOUT\",\"testModule\":\"MCSChangeComplaintsStatus\",\"default\":false},{\"order\":3,\"id\":\"oryx_0CAC0F97-AD57-4C49-807A-B41839191F74\",\"name\":\"Warning\",\"rrcodes\":\"resolution.MCS_CHANGE_COMPLAINTS_STATUS_WARNING\",\"testModule\":\"MCSChangeComplaintsStatus\",\"default\":false},{\"order\":4,\"id\":\"oryx_4583A3EC-DFC8-47B9-9B04-DEE71DC3F17A\",\"name\":\"APIError\",\"rrcodes\":\"resolution.COMPLAINTS_CHANGE_STATUS_FAIL,resolution.MCS_CHANGE_COMPLAINTS_STATUS_FAIL\",\"testModule\":\"MCSChangeComplaintsStatus\",\"default\":true}]}",

它匹配所有这样的表达式:

"resolution.COMPLAINTS_CHANGE_STATUS_SUCCESS

我已经尝试这样打印实例捕获组:

perl -ne 'print "$1\n" if /"resolution.(\w+)/g' FILE_NAME
perl -ne 'print "$1\n" if m/"resolution.(\w+)/sig' FILE_NAME

我希望得到:

OPEN_IT_COMPLAINTS_FOUND
OPEN_IT_COMPLAINTS_NOT_FOUND
MCS_GET_COMPLAINTS_WARNING
MCS_GET_COMPLAINTS_TIMEOUT
MCS_GET_COMPLAINTS_FAIL

但我只得到:

OPEN_IT_COMPLAINTS_FOUND

如果我将上述类型的表达式分别放在文件中的一行中,如下所示:

\"rrcodes\":\"resolution.OPEN_IT_COMPLAINTS_NOT_FOUND1\"
\"rrcodes\":\"resolution.OPEN_IT_COMPLAINTS_NOT_FOUND2\"
\"rrcodes\":\"resolution.OPEN_IT_COMPLAINTS_NOT_FOUND2\"
\"rrcodes\":\"resolution.OPEN_IT_COMPLAINTS_NOT_FOUND4\"

我确实得到了预期的输出:

OPEN_IT_COMPLAINTS_NOT_FOUND1
OPEN_IT_COMPLAINTS_NOT_FOUND2
OPEN_IT_COMPLAINTS_NOT_FOUND2
OPEN_IT_COMPLAINTS_NOT_FOUND4

【问题讨论】:

  • -n 选项对每个输入行执行一次迭代。您没有任何内容可以遍历该行中的所有匹配项。
  • perl -ne 'print "$1\n" for (/"resolution.(\w+)/g)' FILE_NAME
  • 那是 JSON。使用适当的现有 JSON 解析器,即使在单行中也是如此。它将更简单、更清洁、更可靠,而且几乎不再存在。我对甚至没有提到这一点的答案投了反对票。

标签: regex perl


【解决方案1】:

if /.../g 在标量上下文中使用正则表达式。在这种情况下,/.../g 只返回一个匹配项。下一个/.../g 将返回下一个匹配项等:

$ perl -ne '
   print "$1\n" if /"resolution.(\w+)/g; 
   print "$1\n" if /"resolution.(\w+)/g;' file
COMPLAINTS_CHANGE_STATUS_SUCCESS
MCS_CHANGE_COMPLAINTS_STATUS_TIMEOUT

如果您想要所有匹配项,您必须在标量上下文中重复调用 /.../g 或在数组上下文中使用它。第一个选项如下所示:

$ perl -ne 'print "$1\n" while /"resolution.(\w+)/g' file
COMPLAINTS_CHANGE_STATUS_SUCCESS
MCS_CHANGE_COMPLAINTS_STATUS_TIMEOUT
MCS_CHANGE_COMPLAINTS_STATUS_WARNING
COMPLAINTS_CHANGE_STATUS_FAIL

在数组上下文中/.../g 一次将所有匹配项作为数组返回,即

@matches = /"resolution.(\w+)/

在一些命令行语句中,这可能如下所示:

$ perl -ne 'print map { "$_\n" } /"resolution.(\w+)/g' 
COMPLAINTS_CHANGE_STATUS_SUCCESS
MCS_CHANGE_COMPLAINTS_STATUS_TIMEOUT
MCS_CHANGE_COMPLAINTS_STATUS_WARNING
COMPLAINTS_CHANGE_STATUS_FAIL

【讨论】:

  • 非常感谢史蒂芬。这: perl -ne 'print "$1\n" while /"resolution.(\w+)/g' 文件就像一个魅力。
【解决方案2】:

我在您的输入文件中没有看到 OPEN_IT。

尝试循环遍历匹配项:

perl -ne 'print "$_\n" for (/"resolution.(\w+)/g)' FILE_NAME

括号为匹配提供一个列表上下文,for 将设置$_ 为每个匹配一次,并在每个匹配上调用print "$_\n"

【讨论】:

    【解决方案3】:

    标量与列表上下文:

    $ perl -ne 'print "$_\n" foreach (/"resolution\.(\w+)/g)' dummy.txt
    COMPLAINTS_CHANGE_STATUS_SUCCESS
    MCS_CHANGE_COMPLAINTS_STATUS_TIMEOUT
    MCS_CHANGE_COMPLAINTS_STATUS_WARNING
    COMPLAINTS_CHANGE_STATUS_FAIL
    

    /g 仅在正则表达式重复执行时返回多个结果。你的命令行只执行了一次匹配。

    也许下面的代码示例更清楚了;

    #!/usr/bin/perl
    use strict;
    use warnings;
    
    my $re    = qr/string\.(\w+)/;
    my $input = "asdlkj string.TEST1 daklkl string.TEST2 kasöldk";
    
    my($scalar) = ($input =~ /$re/g);
    print "SCALAR: $scalar\n";
    
    my @array   = ($input =~ /$re/g);
    print "ARRAY:  @array\n";
    
    exit 0;
    

    【讨论】:

    • 谢谢斯特凡。这个: perl -ne 'print "$_\n" foreach (/"resolution\.(\w+)/g)' dummy.txt 成功了。
    【解决方案4】:

    这很容易。只需将所有匹配的内容保存在数组中@x:

    perl -ne 'say join "\n",@x if @x=/\"resolution.(\w+)/g' FILE_NAME

    @x 将被评估为真(由if)如果它不为空。

    【讨论】:

    • 我更喜欢这样一种可以节省 for 循环的解决方案(尽可能)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-02-24
    • 2017-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-20
    相关资源
    最近更新 更多