【问题标题】:How to match multiple groups on a specific line in Perl, but not other lines?如何匹配 Perl 中特定行上的多个组,但不匹配其他行?
【发布时间】:2016-11-30 05:21:58
【问题描述】:

我了解 /g 标志,并且可以多次匹配一个模式,但我很难研究这个特定问题。

假设我的字符串有多行,我想匹配包含特定单词的行上的分组模式,但不匹配不包含特定单词的不同行。

以多行字符串$test为例

Unimportant line.
Important line with !special1! word and !special2! word. 
Extra line with !special3! word and !special4! word.

我想在重要行而不是额外行上打印两个特价,所以结果是:

special1, special2  

我可以使用 /g 匹配 每个 特殊的

my @both = $test =~ /!(.+?)!/g;
print join(', ', @both);

但是输出是:

special1, special2, special3, special4

如果我尝试包含“重要”这个词

my @both = $test =~ /Important.+?!(.+?)!/g;
print join(', ', @both);

我刚刚得到

special1

我知道它只匹配一次,因为“重要”只出现一次,但我不知道如何获得输出

special1, special2

【问题讨论】:

  • 如果有多行包含Important会怎样?
  • @Borodin 嗯,我想在我的用例中只会有一行
  • @Borodin 其实我现在很好奇,你怎么会只得到包含重要的第一行
  • @KVon 你在我的回答中有这个。获得匹配后退出循环,这将是第一个。所以在打印后添加last;。 (这假设带有^Important 确实 的行具有模式。否则,添加检查。)

标签: regex perl grouping


【解决方案1】:

有很多方法可以做到这一点。我认为最可靠和最灵活的方法是将字符串分成几行并遍历该数组。然后,您可以在每次迭代中选择如何选择您需要的内容以及您想用它做什么。例如

my @lines = split '\n', $test;

foreach my $line (@lines)
{
    next if $line !~ /^Important/;

    my @all_on_line = $line =~ /!(.+?)!/g;

    if (@all_on_line) 
    {
        print join(', ', @all_on_line), "\n";
    }
}

我假设Important 位于所需行的开头。根据需要进行调整。由于可能对数据进行了更多操作(而不仅仅是打印数据),if 条件会检查该行是否确实具有该模式。

将其打包到一个正则表达式中涉及更多。

【讨论】:

  • 这仅向 print 提供 special 字符串。 OP 的代码会生成一个带有结果的 @both 数组,虽然它会生成 print 的内容,但我想这些字符串实际上是进一步处理所必需的。
  • @Borodin 不知何故错过了之前看到的评论,抱歉。我知道这提供了一个有限的答案,(或多或少)确切地问了什么,如果这就是你的意思。实际上,我考虑添加更多内容,着眼于可能的进一步处理,但由于缺乏相关细节,我看不出什么是足够通用的。
  • 不用担心;我不希望您 24/7 全天候监控网站!我只是认为,当 OP 的代码生成并打印一个数组@both 时,最好复制这种行为。重构您自己的代码来做到这一点并非易事。
  • @Borodin 对,我的意思是我已经“我的椅子和键盘之间的问题”已经有 5 个小时了,但我现在才看到评论。有时会发生,我只是没有发现评论(这很烦人)。
  • @Borodin 但我想我可能看不到你指的是什么。 @both 的 OP 代码在正确的行上工作(除了它的名称错误),但无法区分该行。我认为问题是,只在正确的行上选择项目。我在这里没有看到什么吗?
【解决方案2】:

您可以分两步完成此操作。首先从字符串中分离出Important行,然后搜索special子字符串

这是一个例子。它使用for 作为一个topicaliser,本质上是对($_) = $test =~ /^(.*Important.*)$/m 每次出现Important

请注意,此代码将报告来自 最后一个 包含 Important 的行的数据如果有多个

use strict;
use warnings 'all';

my $test = <<END;
Unimportant line.
Important line with !special1! word and !special2! word. 
Extra line with !special3! word and !special4! word.
END

my @both;
@both = /!([^!]+)!/g for $test =~ /^(.*Important.*)$/m;

print join(', ', @both), "\n";

输出

special1, special2

【讨论】:

    【解决方案3】:

    这对映射功能也很有帮助:

    my @nwlines = map{ $_=~m/^Important(.+?(?=\!special).+?)$/mi } @lines;
    

    【讨论】:

      猜你喜欢
      • 2015-03-25
      • 2020-08-13
      • 2014-12-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-17
      • 1970-01-01
      相关资源
      最近更新 更多