我有一个正则表达式列表(大约10 - 15),我需要匹配一些文本。在循环中逐个匹配它们太慢了。但是,我没有编写自己的状态机来同时匹配所有正则表达式,而是尝试|
单个正则表达式并让perl完成工作。问题是我如何知道哪些替代方案匹配?
这个问题解决了每个正则表达式中没有捕获组的情况。 (which portion is matched by regex?)如果每个正则表达式中都有捕获组,该怎么办?
以下是
/^(A(\d+))|(B(\d+))|(C(\d+))$/
和字符串“A123”,我怎么能知道A123匹配并提取“123”?
答案 0 :(得分:5)
为什么不使用/^ (?<prefix> A|B|C) (?<digits> \d+) $/x
。注意,命名捕获组用于清晰,而不是必需的。
答案 1 :(得分:5)
您不需要编写自己的状态机来组合正则表达式。看看Regexp:Assemble。它有一些方法可以跟踪哪些初始模式匹配。
编辑:
use strict;
use warnings;
use 5.012;
use Regexp::Assemble;
my $string = 'A123';
my $re = Regexp::Assemble->new(track => 1);
for my $pattern (qw/ A(\d+) B(\d+) C(\d+) /) {
$re->add($pattern);
}
say $re->re; ### (?-xism:(?:A(\d+)(?{0})|B(\d+)(?{2})|C(\d+)(?{1})))
say for $re->match($string); ### A(\d+)
say for $re->capture; ### 123
答案 2 :(得分:2)
A123
将位于捕获组$1
中,123
将位于组$2
所以你可以说:
if ( /^(A(\d+))|(B(\d+))|(C(\d+))$/ && $1 eq 'A123' && $2 eq '123' ) {
...
}
这是多余的,但你明白了......
编辑:不,您不必枚举每个子匹配,您询问如何知道A123
是否匹配以及如何提取123
:
if
匹配A123
阻止
123
反向引用来提取$2
。所以也许这个例子会更清楚:
if ( /^(A(\d+))|(B(\d+))|(C(\d+))$/ ) {
# do something with $2, which will be '123' assuming $_ matches /^A123/
}
编辑2:
要捕获AoA中的匹配(这是一个不同的问题,但这应该这样做):
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
my @matches = map { [$1,$2] if /^(?:(A|B|C)(\d+))$/ } <DATA>;
print Dumper \@matches;
__DATA__
A123
B456
C769
结果:
$VAR1 = [
[
'A',
'123'
],
[
'B',
'456'
],
[
'C',
'769'
]
];
请注意,我修改了你的正则表达式,但看起来你的评论就是这样......
答案 3 :(得分:1)
使用您的示例数据,可以轻松编写
'A123' =~ /^([ABC])(\d+)$/;
之后$ 1将包含前缀,$ 2将包含后缀。
我无法判断这是否与您的实际数据相关,但是使用额外的模块似乎有些过分。
答案 4 :(得分:0)
你可以在Perl中做的另一件事是使用&#34;(?{...})&#34;直接在你的正则表达式中嵌入Perl代码。因此,您可以设置一个变量来告诉您正则表达式的哪个部分匹配。警告:你的正则表达式不应该包含任何变量(在嵌入的Perl代码之外),它将被插入到正则表达式中,否则你将得到错误。以下是使用此功能的示例解析器:
my $kind;
my $REGEX = qr/
[A-Za-z][\w]* (?{$kind = 'IDENT';})
| (?: ==? | != | <=? | >=? ) (?{$kind = 'OP';})
| -?\d+ (?{$kind = 'INT';})
| \x27 ( (?:[^\x27] | \x27{2})* ) \x27 (?{$kind = 'STRING';})
| \S (?{$kind = 'OTHER';})
/xs;
my $line = "if (x == 'that') then x = -23 and y = 'say ''hi'' for me';";
my @tokens;
while ($line =~ /( $REGEX )/xsg) {
my($match, $str) = ($1,$2);
if ($kind eq 'STRING') {
$str =~ s/\x27\x27/\x27/g;
push(@tokens, ['STRING', $str]);
}
else {
push(@tokens, [$kind, $match]);
}
}
foreach my $lItems (@tokens) {
print("$lItems->[0]: $lItems->[1]\n");
}
打印出以下内容:
IDENT: if
OTHER: (
IDENT: x
OP: ==
STRING: that
OTHER: )
IDENT: then
IDENT: x
OP: =
INT: -23
IDENT: and
IDENT: y
OP: =
STRING: say 'hi' for me
OTHER: ;
它有点做作,但是你会注意到字符串周围的引号(实际上是撇号)被剥离了(连续引号也折叠成单引号),所以一般来说,只有$ kind变量将告诉您解析器是否看到了标识符或带引号的字符串。