在 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',
'!'
];
===
代码注释中有更多详细信息。输出位于代码部分的底部。还有'!'性格就是这样。我没有将它与其他一些东西混淆。
我知道这应该很容易,但是...
在交替中,all 捕获的值被返回,即使是那些不匹配的。
一个简单的方法是从返回列表中过滤掉
undef
的
if (my @v = grep { defined } $s =~ /^(?: (\S+)(=)([fisuo]) | (\S+)(!) )$/x)
还有其他方法可以构建正则表达式,但直接交替就可以了。
我们可以使用以下单个正则表达式模式:
^(\S+)([!=])((?<==)[fisuo])?$
这表示匹配:
^
从字符串的开头(\S+)
匹配并捕获 $1
一个非空白术语([!=])
在$2
中匹配并捕获!
或=
((?<==)[fisuo])?
然后在$3
中选择性地捕获来自fisuo
的一封信
后视(?<==)
确保这只匹配=
$
字符串的结尾因为你要匹配两个不同的东西,所以有两个不同的匹配似乎是完全合理的。
但是,如果你想把它们结合起来,你可以这样做:
m{^
(\S+)
(?:
=([fisuo]) |
(!)
)
$
}x
$1 是名字。 $2 是开关,如果存在的话。 $3 是 !,如果存在的话。
对于任何更复杂的事情,使用named captures或Regexp::Assemble.