Raku regex:如何知道轮流捕获哪个组

问题描述

使用perl(以及几乎任何正则表达式),每个组都按顺序编号。

例如,这段代码:

'bar' =~ m/(foo)|(bar)/;

print $1 // 'x'; # (1-based index)
print $2 // 'x'; # (1-based index)

打印xbar

但是,对于Raku,它的行为就像是branch reset group包裹了整个正则表达式:

'bar' ~~ m/(foo)|(bar)/;

print $0 // 'x'; # (0-based index)
print $1 // 'x'; # (0-based index)

打印barx

我可以接受这种行为:)。但是,有时知道知道在交替下捕获了哪个组很有用。

我怎么知道有乐团的人?

解决方法

有几种方法可以实现不同程度的实用性。

一种方法是明确告诉Raku您希望数字是什么:

'bar' ~~ m/$1=(foo)|$2=(bar)/;

如果您扩展正则表达式,计数将继续在$ 3。

一种不太推荐的方法是偷偷地套上一个括号:

'bar' ~~ m/(foo)|()(bar)/;

foo将匹配$ 0中的第一个,并且$ 1将是未定义的,而bar将匹配$ 1,其中$ 0为空(但不是未定义)。 TIMTOWTDI,但这不是一个很好的;-)

另一种方法是使用标志:

 my $flag;
'bar' ~~ m/(foo {$flag = 'first'} ) | (bar {$flag = 'second'} )/;

将根据匹配设置标志。实际上这可能是一种不可怕的处理方式,尤其是如果您的标志是二进制的并且您将有一些逻辑可以运行它的话。

另一种类似的方法是利用通常在动作类中使用的.make / .made,但仍可以内联使用:

'bar' ~~ m/(foo {make 'first'} ) | (bar {make 'second'} )/;
say $0.made; # 'second'

如果您有很多要与之关联的元数据,那么这是一个不错的选择(但是,仅知道选择了哪个元数据可能就太过分了。)

,

有些事情会导致捕获索引重置。 |||恰好是一个。

将其放入另一个捕获组中是另一个。 (因为匹配结果是一棵树。)


在设计Raku时,所有内容都进行了重新设计,以使其更加一致,更加有用和强大。包含正则表达式。

如果您有其他类似的东西:

/  (foo)  |  (bar)  /

您可能想像这样使用它:

$line ~~ /  (foo)  |  (bar)  /;
say %h{ ~$0 };

如果(bar)$1,则必须这样写:

$line ~~ /  (foo)  |  (bar)  /;
say %h{ ~$0 || ~$1 };

对于捕获组编号,从零开始重新编号通常更为有用。

这也使得正则表达式更像是通用编程语言。 (每个“ block”是一个独立的子表达式。)


现在,有时最好对捕获组重新编号。

/ ^
[   (..) '-'  (..) '-' (....)  # mm-dd-yyyy
|   (..) '-' (....)            # mm-yyyy
]
$ /

请注意,yyyy部分是$2还是$1,具体取决于是否包含dd部分。

my $day   = +$2 ?? $1 !! 1;
my $month = +$0;
my $year  = +$2 || +$1;

我们可以将yyyy重新编号为始终为$2

/ ^
[   (..) '-'  (..) '-' (....)  # mm-dd-yyyy
|   (..) '-' $2 = (....)       # mm-yyyy
]
$ /

my $day   = +$1 || 1;
my $month = +$0;
my $year  = +$2;

或者如果我们还需要接受yyyy-mm-dd

/ ^
[   (..) '-' (..) '-' (....)                # mm-dd-yyyy
|   (..) '-' $2 = (....)                    # mm-yyyy
|   $2 = (....) '-' $0 = (..) '-' $1 = (..) # yyyy-mm-dd
]
$ /

my $day   = +$1 || 1
my $month = +$0;
my $year  = +$2;

实际上,现在我们有很多捕获组,让我们再看一下如果|不会导致编号的捕获组从$0重新开始的处理方式

/ ^
[   (..) '-' (..) '-' (....) # mm-dd-yyyy
|   (..) '-' (....)          # mm-yyyy
|   (....) '-' (..) '-' (..) # yyyy-mm-dd
]
$ /

my $day   = +$1 || +$7 ||   1;
my $month = +$0 || +$3 || +$6;
my $year  = +$2 || +$4 || +$5;

那不是很好。
一方面,您必须确保正则表达式和my $day正确匹配。

要快速进行而无需计算捕获组,请确保这些数字与正确的捕获组匹配。


当然,仍然存在一个问题,即用数字捕获具有名称的概念。

所以我们应该改用名称。

/ ^
[   $<month> = (..) '-' $<day> = (..) '-' $<year> = (....) # mm-dd-yyyy
|   $<month> = (..) '-' $<year> = (....)                   # mm-yyyy
|   $<year> = (....) '-' $<month> = (..) '-' $<day> = (..) # yyyy-mm-dd
]
$ /

my $day   = +$<day> || 1;
my $month = +$<month>;
my $year  = +$<year>;

长话短说,我会这样做:

/ $<foo> = (foo)  |  $<bar> = (bar) /;


if $<foo> {
    …
} elsif $<bar> {
    …
}

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...