命名捕获组中的顺序

时间:2014-12-10 07:40:27

标签: regex perl

我最近在regexp中发现了命名捕获组的强大功能。不幸的是,似乎我不能以不同的顺序使用它们。

让我们考虑这个短价格表:

 15 USD
 CHF 18

我想检索货币及其价值。所以,我天真地写了这个:

(?|
(?<value>\d+)\s*(?<currency>[a-z]+)
|
(?<currency>[a-z]+)\s*(?<value>\d+)
)

不幸的是,在这里可见(https://regex101.com/r/uE8qE1/1),正则表达式有错误。但是,我在Perl中没有收到任何错误,我可以访问$+{currency}$+{value},但我有时会将货币输入值,反之亦然。

有没有办法在叮咬中捕捉混合元素?

修改

以下是Perl中显示问题的示例:

#!/usr/bin/env perl
use 5.014;

my $_ = "14 USD
CHF 15";

while(/(?|
(?<value>[0-9]+)\s*(?<currency>[a-z]+)
|
(?<currency>[a-z]+)\s*(?<value>[0-9]+)
)/igmx) {
    say "Currency: $+{currency}\tValue: $+{value}";
}           

输出:

$ ./test.pl
Currency: USD   Value: 14
Currency: 15    Value: CHF  

2 个答案:

答案 0 :(得分:1)

看起来分支重置模式会混淆正则表达式引擎。

use strict;
use warnings;
use 5.010;

while (<DATA>) {
  next unless /(?<value>\d+)\s*(?<currency>[a-z]+) | (?<currency>[a-z]+)\s*(?<value>\d+)/ix;
  say "$+{value} $+{currency}";
}

__DATA__
15 USD
CHF 18

<强>输出

15 USD
18 CHF

<强>更新

@PatrickJ.S.非常有帮助,指出在&#34;扩展模式&#34; 下的perlre中记录了这种情况。 分支重置部分说明了这一点。粗体是我自己的。

  

将分支重置模式与命名捕获结合使用时要小心。命名捕获被实现为包含捕获的编号组的别名,并且干扰分支重置模式的实现。 如果您在分支重置模式中使用命名捕获,则最好在每个替换中以相同的顺序使用相同的名称

据我所知,当有多个具有相同名称的命名捕获时,没有提及任何行为,所以即使你按照预期的那样工作,你也处于非常不稳定的状态。

答案 1 :(得分:1)

对于任何试图使用以任何顺序匹配的捕获组(特别是命名的捕获组)的人,我的建议是提前进行捕获:

[See it working here]

use 5.014;

$_ = "
CHF 15
14 USD
";

while(/(?=.*?\b(?<value>[0-9]+)\b)(?=.*?\b(?<currency>[a-z]+)\b)/igmx) {
    say "Currency: $+{currency}\tValue: $+{value}";
}

产生

Currency: CHF   Value: 15
Currency: USD   Value: 14