用捕获组合并两个正则表达式(PCRE/perl)

问题描述 投票:0回答:3

在 perl 中,我试图匹配其中一个

(\S+)(=)([fisuo])

(\S+)(!)

然后将结果放在列表中(捕获组)。我所有的尝试都会导致额外的、不需要的捕获。

这是一些代码:

#!/usr/bin/perl
#-*- cperl -*-
# $Id: test7,v 1.1 2023/04/10 02:57:12 bennett Exp bennett $
#

use strict;
use warnings;
use Data::Dumper;

foreach my $k ('debugFlags=s', 'verbose!') {
    my @v;

    # Below is the offensive looking code.  I was hoping for a regex
    # which would behave like this:

    if(@v = $k =~ m/^(\S+)(=)([fisuo])$/) {
      printf STDERR ("clownMatch = '$k' => %s\n\n", Dumper(\@v));
    } elsif(@v = $k =~ m/^(\S+)(!)$/) {
      printf STDERR ("clownMatch = '$k' => %s\n\n", Dumper(\@v));
    }

    @v = ();

    # This is one of my failed, aspirational matches.  I think I know
    # WHY it fails, but I don't know how to fix it.
    
    if(@v = $k =~ m/^(?:(\S+)(=)([fisuo]))|(?:(\S+)(!))$/) {
      printf STDERR ("hopefulMatch = '$k' => %s\n\n", Dumper(\@v));
    }
    printf STDERR "===\n";
}

exit(0);
__END__
Output:
clownMatch = 'debugFlags=s' => $VAR1 = [
          'debugFlags',
          '=',
          's'
        ];


hopefulMatch = 'debugFlags=s' => $VAR1 = [
          'debugFlags',
          '=',
          's',
          undef,
          undef
        ];


===
clownMatch = 'verbose!' => $VAR1 = [
          'verbose',
          '!'
        ];


hopefulMatch = 'verbose!' => $VAR1 = [
          undef,
          undef,
          undef,
          'verbose',
          '!'
        ];


===

代码注释中有更多详细信息。输出位于代码部分的底部。还有'!'性格就是这样。我没有将它与其他一些东西混淆。

我知道这应该很容易,但是...

regex perl regex-group
3个回答
1
投票

在交替中,all 捕获的值被返回,即使是那些不匹配的。

一个简单的方法是从返回列表中过滤掉

undef

if (my @v = grep { defined } $s =~ /^(?: (\S+)(=)([fisuo]) | (\S+)(!) )$/x)

还有其他方法可以构建正则表达式,但直接交替就可以了。


1
投票

我们可以使用以下单个正则表达式模式:

^(\S+)([!=])((?<==)[fisuo])?$

这表示匹配:

  • ^
    从字符串的开头
  • (\S+)
    匹配并捕获
    $1
    一个非空白术语
  • ([!=])
    $2
    中匹配并捕获
    !
    =
  • ((?<==)[fisuo])?
    然后在
    $3
    中选择性地捕获来自
    fisuo
    的一封信 后视
    (?<==)
    确保这只匹配
    =
  • $
    字符串的结尾

演示


1
投票

因为你要匹配两个不同的东西,所以有两个不同的匹配似乎是完全合理的。

但是,如果你想把它们结合起来,你可以这样做:

m{^
  (\S+)
  (?:
    =([fisuo]) |
    (!)
  )
  $
}x

$1 是名字。 $2 是开关,如果存在的话。 $3 是 !,如果存在的话。

对于任何更复杂的事情,使用named capturesRegexp::Assemble.

示范

© www.soinside.com 2019 - 2024. All rights reserved.