所有好东西都是三个(如何跳过不需要的子匹配?)

时间:2012-07-31 11:58:25

标签: regex perl

如何使用/跳过不需要的匹配?

让我们假设我们有以下文字:

my $t ='good good *bad !bad -bad "alwaysbad alwaysbad alwaysbad" good';

我想要一个只匹配good个单词的正则表达式。当然,符号词goodbadalwaysbad的真实内容是[0-9A-Za-z_@]+\w+对此问题没问题)。要告诉bad单词中的good单词,单词开头的(\s|^)\b\w就足够了。双引号中的东西总是一个坏词,即使没有前缀。

这就是我所拥有的:

my $r = qr/
           (?: " [^"]+ " )     # skip quoted part altogether, don't capture
            |                  # OR
           (?<!\S) \b ([\w@]+) # find words without 'bad' prefix and capture
          /x;

此表达式不会捕获引用的部分,但仍然匹配。因此,我们在匹配列表中会有一个undefined空条目:

my @matches = $t =~ /$r/g;

print join "\n", @matches;

  good
  good
         <== (uninitialized value, this comes from the quoted part)
  good

现在的问题是:

是否有人知道适用于当前perl正则表达式的技术如何使用单个正则表达式调用来消耗字符串的给定部分但不匹配

因此,结果应为:

  good
  good
  good

<小时/> 的附录

感谢Borodins answer,我现在看得更清楚了。只需删除|(或)并应用任何or-zero-times量词,就可以了:

my $r = qr/
           (?: " [^"]+ ")? \s?  # skip quotes + space if any
           (?<!\S) \b ([\w@]+)  # find words without 'bad' prefix and capture
          /x;

2 个答案:

答案 0 :(得分:2)

你的正则表达式只匹配非捕获序列,因为你说的就是你想要的。

使用插入的非引号字符编写任意数量的带引号字符串的可选前缀,例如

my $r = qr/
  (?: " [^"]* " [^"]*?)*    # skip quoted part altogether, don't capture
  (?<!\S) \b (\w+)          # find words without 'bad' prefix and capture
/x;

但为了清楚起见,我会在尝试匹配之前从目标中删除所有引用的字符串。不要忘记,如果您想在子字符串中同时允许@,那么您需要[\w@]。并且您还需要进行尾随检查以确保在开头之后没有无效字符

$t =~ s/"[^"]*"//g;
my @matches = $t =~ /(?:\s|^)[\w\@]+(?=\s|\z)/g;

答案 1 :(得分:1)

你可以过滤掉它们:

my @matches = grep { m/\S/ } $t =~ /$r/g;