Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Perl, 'Use of uninitialized value in substitution iterator' error for $1 variable

Tags:

regex

perl

Working from an example found else where on stackoverflow.com I am attempting to replace on the Nth instance of a regex match on a string in Perl. My code is as follows:

#!/usr/bin/env perl
use strict;
use warnings;

my $num_args = $#ARGV +1;
if($num_args != 3) {
        print "\nUsage: replace_integer.pl occurance replacement to_replace";
        print "\nE.g. `./replace_integer.pl 1 \"INTEGER_PLACEHOLDER\" \"method(0 , 1, 6);\"`";
        print "\nWould output: \"method(INTEGER_PLACEMENT , 1, 6);\"\n";
        exit;
}

my $string =$ARGV[2];

my $cont =0;
sub replacen { 
        my ($index,$original,$replacement) = @_;
        $cont++;
        return $cont == $index ? $replacement: $original;
}

sub replace_quoted {
        my ($string, $index,$replacement) = @_;
        $cont = 0; # initialize match counter
        $string =~ s/[0-9]+/replacen($index,$1,$replacement)/eg;
        return $string;
}

my $result = replace_quoted ( $string, $ARGV[0] ,$ARGV[1]);
print "RESULT: $result\n";

For

./replace_integer.pl 3 "INTEGER_PLACEHOLDER" "method(0, 1 ,6);"

I'd expect an output of

RESULT: method(0, 1 ,INTEGER_PLACEHOLDER);

Unfortunately I get an output of

RESULT: method(,  ,INTEGER_PLACEHOLDER);

With these warnings/errors

Use of uninitialized value in substitution iterator at ./replace_integer.pl line 26.
Use of uninitialized value in substitution iterator at ./replace_integer.pl line 26.

Line 26 is the following line:

$string =~ s/[0-9]+/replacen($index,$1,$replacement)/eg;

I have determined this is due to $1 being uninitialised. To my understanding $1 should have the value of the last match. Given my very simple regex ([0-9]+) I see no reason why it should be uninitialised.

I am aware there are easier ways to find and replace the Nth instance in sed but I will require Perl's back and forward references once this hurdle is overcome (not supported by sed)

Does anyone know the cause of this error and how to fix it?

I am using Perl v5.18.2 , built for x86_64-linux-gnu-thread-multi

Thank you for your time.


2 Answers

$1 is only set after you capture a pattern, for example:

$foo =~ /([0-9]+)/;
# $1 equals whatever was matched between the parens above

Try wrapping your matching in parens to capture it to $1

like image 85
skarface Avatar answered Oct 21 '25 17:10

skarface


I would write it like this

The while loop iterates over occurrences of the \d+ pattern in the string. When the Nth occurrence is found the last match is replaced using a call to substr using the values in built-in arrays @- (the start of the last match) and @+ (the end of the last match)

#!/usr/bin/env perl

use strict;
use warnings;

@ARGV = ( 3, 'INTEGER_PLACEHOLDER', 'method(0, 1, 6);' );

if ( @ARGV != 3 ) {
    print qq{\nUsage: replace_integer.pl occurrence replacement to_replace};
    print qq{\nE.g. `./replace_integer.pl 1 "INTEGER_PLACEHOLDER" "method(0 , 1, 6);"`};
    print qq{\nWould output: "method(INTEGER_PLACEMENT , 1, 6);"\n};
    exit;
}

my ( $occurrence, $replacement, $string ) = @ARGV;

my $n;
while ( $string =~ /\d+/g ) {

    next unless ++$n == $occurrence;

    substr $string, $-[0], $+[0]-$-[0], $replacement;
    last;
}

print "RESULT: $string\n";

output

$ replace_integer.pl 3 INTEGER_PLACEHOLDER 'method(0, 1, 6);'
RESULT: method(0, 1, INTEGER_PLACEHOLDER);

$ replace_integer.pl 2 INTEGER_PLACEHOLDER 'method(0, 1, 6);'
RESULT: method(0, INTEGER_PLACEHOLDER, 6);

$ replace_integer.pl 1 INTEGER_PLACEHOLDER 'method(0, 1, 6);'
RESULT: method(INTEGER_PLACEHOLDER, 1, 6);
like image 43
Borodin Avatar answered Oct 21 '25 17:10

Borodin



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!