10

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

例如,这段代码:

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

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

印刷xbar

但是,对于 Raku,它的行为就像有一个分支重置组包装了整个正则表达式:

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

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

印刷barx

我对这种行为没意见:)。但是,有时了解在交替下捕获了哪个组是有用的。

我怎样才能知道有 raku 的组?

4

2 回答 2

10

有几种方法可以做,具有不同程度的效用。

一种方法是明确告诉 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'

如果您有很多想要与之关联的元数据,这个很好(但可能因为只知道选择了哪一个而过度杀伤)。

于 2020-10-16T20:28:44.977 回答
2

有几件事会导致捕获索引重置。|并且||恰好是一个。

将它放在另一个捕获组中是另一回事。(因为匹配结果是一棵树。)


在设计 Raku 时,所有东西都经过重新设计,变得更一致、更有用、更强大。包括正则表达式。

如果你有这样的替代:

/  (foo)  |  (bar)  /

您可能希望像这样使用它:

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

如果(bar)$1,你将不得不这样写:

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

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

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


现在有时重新编号捕获组可能会很好。

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

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

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

我们可以将 重新编号yyyy为 always be $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> {
    …
}
于 2020-10-17T19:57:35.470 回答