Ludisposed
Ludisposed

Reputation: 1769

Perl captured digits from string are always 1

On my journey to start learning perl...

I encountered this funny behaviour, and can't seem to wrap my head around it.

my $username = "bandit0";
my $command = "";

sub next_command {
    my ($user) = @_;
    my $num = $user =~ /(\d+)/;
    print "$num\n";
    if ($num == 0){
        return "cat readme";
    }
    elsif ($num == 1){
        return "ls";
    }
}

sub next_level {
    my ($user) = @_;
    my $num = $user =~ /(\d+)/;
    $user =~ s/\d//g;
    $user = $user . $num++;
    return $user;
}

$command = next_command($username);
print $command . "\n";
$username = next_level($username);
$command = next_command($username);
print $command . "\n";

After running this small perl program, I would expect something like this:

0
cat readme
1
ls

However I get something like this...

1
ls
1
ls

I don't understand why, at first string bandit0 the $num will be 1 instead of 0

Upvotes: 0

Views: 89

Answers (2)

user7818749
user7818749

Reputation:

You can try this and see if it works. if it helps, I will explain everything. I cannot test this myself right now.

use strict;   # always use strict
use warnings; # always use warnings

my $username = "bandit0"; #try bandit1 to ensure it prints 1 and ls instead
my $command = "";

sub next_command {
    my ($user) = @_;
    my ($num) = $user =~ /(\d+)/;
    print "$num\n";
    if ($num == 0){
       return "cat readme";
    }

    elsif ($num == 1){
        return "ls";
    }
}

sub next_level {
    my ($user) = @_;
    my ($num) = $user =~ /(\d+)/;
    $user =~ s/\d//g;
    $user = $user . ++$num;
     return $user;
}

$command = next_command($username);
print $command . "\n";
$username = next_level($username);
$command = next_command($username);
print $command . "\n";

Upvotes: 2

ikegami
ikegami

Reputation: 386426

The match operator in scalar context evaluates to a boolean that indicates whether the match succeeded or not.

my $success = $user =~ /(\d+)/;

The match operator in list context returns the captured strings (or 1 if there are no captures) on success and an empty list on error.

my ($num) = $user =~ /(\d+)/;

You used the former, but you want the latter. That gives you the following (after a few other small fixes):

sub next_level {
    my ($user) = @_;
    my ($num) = $user =~ /(\d+)\z/;
    $user =~ s/\d+\z//g;
    $user .= ++$num;
    return $user;
}

But that approach is complicated and inefficient. Simpler solution:

sub next_level {
    my ($user) = @_;
    $user =~ s/(\d+)\z/ $1 + 1 /e;
    return $user;
}

Upvotes: 3

Related Questions