Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

Substitute _last_ occurence in string?

by Anonymous Monk
on Jul 25, 2001 at 18:23 UTC ( [id://99682]=perlquestion: print w/replies, xml ) Need Help??

Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I'd like to know a short way to substitute the last occurence of a substring within a string. For instance, $string = "one two three two four"; $string =~ s/two // would return "one three two four". What would return: "one two three four"? Thanks, Paul.

Replies are listed 'Best First'.
Re: Substitute _last_ occurence in string?
by voyager (Friar) on Jul 25, 2001 at 18:30 UTC
    How about:
    $string = "one two three two four"; $gnirts = reverse $string; $gnirts =~ s/ owt//; $string = reverse $gnirts;
    Reverse the string, remove the reverse of the desired token, then reverse the result.

    Update: Full disclosure -- this was motivated by a node on sexeger I saw before. Props to japhy.

    Update2: Fixed typo -- thanks Hofmator.

Re: Substitute _last_ occurence in string?
by Hofmator (Curate) on Jul 25, 2001 at 18:38 UTC

    Or for searching for strings (this does not work for patterns) you can use rindex:

    my $string = 'one two three two four'; my $search = 'two '; substr($string, rindex($string,$search), length $search, ''); print $string;

    -- Hofmator

Re: Substitute _last_ occurence in string?
by japhy (Canon) on Jul 25, 2001 at 19:18 UTC
    I'm glad people took the sexeger approach, for which this is an excellent example. Other approaches, like:
    • s/two(?!.*two)//, and
    • s/two(?!.*?two)//, and
    • s/.*two//
    suffer from things like slowness and too much backtracking.

    _____________________________________________________
    Jeff japhy Pinyan: Perl, regex, and perl hacker.
    s++=END;++y(;-P)}y js++=;shajsj<++y(p-q)}?print:??;

Re: Substitute _last_ occurence in string?
by MZSanford (Curate) on Jul 25, 2001 at 18:31 UTC
    might use (untested):
    $string = reverse($string); $string =~ s/owt //; $string = reverse($string);

    Thus spake the Master Programmer:
    "When you have learned to snatch the error code from the trap frame, it will be time for you to leave."
    -- The Tao of Programming
Re: Substitute _last_ occurence in string?
by PrakashK (Pilgrim) on Jul 25, 2001 at 18:40 UTC
    s/(two )(?!.*two )//
    Probably valid only perl 5.6.0 +. Update: Above works only if two is followed by a space. It fails if:
    $string = "one two three two four two";
    The following works. Also, the parentheses around the first two are unnecessary.
    $string =~ s/two\s*(?!.*two)//
Re: Substitute _last_ occurence in string?
by Wookie (Beadle) on Jul 25, 2001 at 18:46 UTC
    You can try to use the fact that '*' is greedy:
    $string=~s/(.*) two(.*)/$1$2/g;
    When the first '.*' matches - it should go to the end of the line - and then work right to left to match the next part of the regex.

    So in this case - it should find the last one.
    game(Wookie,opponent) eq 'Wookie' ? undef $problem : remove_limbs(arms,opponent);

      This can be expressed a little bit simpler: $string=~s/(.*) two/$1/; The /g modifier is not necessary - there will be only one match. And you don't want to change anything after the match so you don't have to capture and replace it.

      -- Hofmator

        This assumes that there is more than one 'two'. If there's only one instance, then the first instance is the last instance. I'd change this to:

        $string =~ s/(.*)\s*two/$1/; That way, you'll catch it if it's the first characters in the string.

        Update: Ok. Given the suggestions, How about:

        $string =~ s/(.*)(^|\s+)two/$1/;

Re: Substitute _last_ occurence in string?
by scain (Curate) on Jul 25, 2001 at 18:37 UTC
    Hello,

    $string =~ s/two (.*?)$/$1/ should work, though after a little testing, I find that it does not. I don't know why. Anyone?

    Scott

    Update: I must admit, I like the trickyness of using the reverse.

      Regexes always give you the leftmost longest match. To do something like you want you best use the greediness of .* $string =~ s/(.*) two/$1/;

      Update: I have simplified the unnecessarily complicated regex.

      -- Hofmator

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://99682]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others surveying the Monastery: (4)
As of 2024-04-23 23:07 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found