Perl:命名捕获组默认为替换字符串

mca*_*ria 5 regex perl capture-group

以下 Perl 代码在第二次尝试取消引用捕获组“ext”时失败

use strict;
use warnings;

foreach(qw/2.1 2/){
#foreach(@ARGV){
    my $out= sprintf("%.2f", $_);
    $out =~ s/(?:(?<ext>\.[1-9]?)|\.0)0([^\w]|$)/$+{'ext'}/g;
    print ":".$out.":\n";
}
Run Code Online (Sandbox Code Playgroud)

如果未定义替换字符串中的捕获组,如何设置默认值?

我确信还有其他几种方法可以解决这个问题,但我相信无法为捕获组设置默认值肯定会再次出现 - 所以请帮我解决这个问题。

跟进:

..我在池上建议的帮助下让它工作,所以它读

$out =~ s{(?:(?<ext>\.[1-9]?)|\.0)0([^\w]|$)}{ $+{'ext'} // "" }eg;
Run Code Online (Sandbox Code Playgroud)

……难道就没有别的办法了吗?特别是因为这只适用于 Perl 的“e”评估正则表达式功能。这也必须以标准正则表达式的方式出现,如果一开始就没有捕获的话,至少要忽略捕获组解除引用,不是吗?

ike*_*ami 6

使用修饰符使替换部分成为表达式e

s{...}{ $+{ext} // "default" }eg
Run Code Online (Sandbox Code Playgroud)

但是,您想要实现的目标不需要使用捕获,更不用说条件捕获和它们的默认值了。

您似乎正在尝试删除所有尾随零以及.之后可能保留的尾随。为此,您可以使用以下简单代码:

my $out = sprintf( "%.2f", $_ ) =~ s/0+\z//r =~ s/\.\z//r;
Run Code Online (Sandbox Code Playgroud)

另一种看待它的方式是只能删除两个子字符串:.00在末尾,或0在末尾。这为我们提供了以下解决方案:

my $out = sprintf( "%.2f", $_ ) =~ s/\.00\z|0\z//r;
Run Code Online (Sandbox Code Playgroud)


小智 2

如果您坚持为此使用命名组...
而不是使用修饰符,只需在交替上下文中e定义一个空即可。ext

use strict;
use warnings;

foreach(qw/2.1 2/){
    my $out= sprintf("%.2f", $_);
    $out =~ s/(?:(?<ext>\.[1-9]?)|(?<ext>)\.0)0([^\w]|$)/$+{'ext'}/g;
    print ":".$out.":\n";
}
Run Code Online (Sandbox Code Playgroud)

输出

:2.1:
:2:
Run Code Online (Sandbox Code Playgroud)

更简单的是,取消命名捕获并使用Branch Reset
使用时保持便携。

use strict;
use warnings;

foreach(qw/2.1 2/){
#foreach(@ARGV){
    my $out= sprintf("%.2f", $_);
    $out =~ s/(?|(\.[1-9]?)|()\.0)0([^\w]|$)/$1/g;
    print ":".$out.":\n";
}
Run Code Online (Sandbox Code Playgroud)

相同的输出

:2.1:
:2:
Run Code Online (Sandbox Code Playgroud)

有关详细信息,请参阅此处已接受的答案: How to escape warnings in Perl regex replacement with Alternatives?