Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical

Problem with substr

by newbie1991 (Acolyte)
on May 14, 2013 at 15:50 UTC ( #1033511=perlquestion: print w/replies, xml ) Need Help??
newbie1991 has asked for the wisdom of the Perl Monks concerning the following question:

Hi, I have a list of names that I am trying to clean up. Some of them have ".replaced" after the name, which I am trying to remove. The code I am using is this :

$name = substr $name, 0, rindex( $name, q{replaced} );
The line works just fine for the names that are followed by the "replaced", however, the last letter of the name gets cut off if the name is not followed by "replaced". e.coli.replaced becomes e.coli (which is fine), but z.mays becomes z.may (which isn't). How can I fix this?

Replies are listed 'Best First'.
Re: Problem with substr
by marto (Archbishop) on May 14, 2013 at 16:00 UTC

    "e.coli.replaced becomes e.coli (which is fine)

    It doesn't. With your code it becomes "e.coli.".

    "but z.mays becomes z.may (which isn't)."

    Don't assume what rindex returns, try this for your test case:

    print rindex( $name, q{replaced} );

    A simpler way of doing this would be:

    my $name = "e.coli.replaced"; $name =~ s/.replaced//;

    Should you actually wish the outcome to be as you specified and not what your code actually does.

    Update: Fixed typo

    Update 2: Dang, this is a must read, catches my mistake.

      $name =~ s/.replaced//;

      Note that the  . (dot) in the quoted regex is the metacharacter for the operation "match any character except a newline" and as such will occasionally fail to do what newbie1991 wants. I suggest something like
          $name =~ s/\.replaced//;
      in which the dot is escaped to remove its meta-magic and make it match only a lowly period.

      >perl -wMstrict -le "my $name = 'e.coliXreplaced'; $name =~ s/.replaced//; print qq{'$name'}; " 'e.coli'
      Switching to s/// did the trick. Thanks :)
Re: Problem with substr
by kennethk (Abbot) on May 14, 2013 at 16:03 UTC
    If rindex has no matches, it returns -1. If substr gets a negative OFFSET, it "starts that far back from the end of the string". The correct approach here would be to test the result of rindex, and only modify if the number is non-negative:
    if ((my $index = rindex( $name, q{.replaced})) > -1 ) { $name = substr $name, 0, $index; }

    Note as well that you have an off-by-one error on your replacement, which I have fixed by adding '.' to your string.

    Update: AnomalousMonk caught that the rindex was in the LENGTH argument, not the OFFSET argument.

    If LENGTH is negative, leaves that many characters off the end of the string.

    #11929 First ask yourself `How would I do this without a computer?' Then have the computer do it the same way.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1033511]
Approved by marto
[marto]: good morning all

How do I use this? | Other CB clients
Other Users?
Others exploiting the Monastery: (9)
As of 2018-06-20 08:40 GMT
Find Nodes?
    Voting Booth?
    Should cpanminus be part of the standard Perl release?

    Results (116 votes). Check out past polls.