regexperlcapture-group

Perl: named capturing group defaults at replacement string


The following Perl code fails on the second attempt of dereferencing the capturing group "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";
}

How can I set a default for the capturing group within the replacement string in case it doesn't get defined?

I'm sure there are several other ways to solve this problem, but not being able to set a default value for a capture group will surely come up another time again I believe - so please help me figure this out.

FOLLOWUP:

..I got it to work with the help of ikegami's advice, so that it reads

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

...it's just isn't there another way? Especially since this only works with Perl's "e"valuate regex functionality. This must come up in standard regex way as well, to at least ignore the capture group dereferencing if it wasn't captured in the first place, no?


Solution

  • If you insist on using Named groups for this...
    Instead of using the e modifier, just define an empty ext in the alternation context.

    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";
    }
    

    Output

    :2.1:
    :2:
    

    Even easier, do away with the named capture and use a Branch Reset.
    Keep it portable in usage.

    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";
    }
    

    Same output

    :2.1:
    :2:
    

    See the accepted answer here for details: How to avoid warnings in Perl regex substitution with alternatives?