Matching final occurance of a string in text

Discussion in 'Perl Misc' started by Stephen O'D, Jun 1, 2005.

  1. Stephen O'D

    Stephen O'D Guest

    Hi,

    I can't believe I cannot get this to work, as it seems so simple, but I
    am so far stumped.

    I have a variable (two different cases):-

    my $text = "foo_errors_bar";
    my $text = "foo_errors_bar_errors_foobar";

    I need to substitute the final 'errors' out of the string leaving me
    with:-

    $text = 'foo__bar';
    $text = 'foo_errors_bar__foobar';

    $text =~ s/errors(.+)$/$1/

    Does not work, as it grabs the first 'errors'.

    So I tried:-

    $text =~ s/errors([^(?:errors)]+)$/$1/

    Which does not work at all (I thought this would translate rougly into
    english as "find errors followed by one or more not errors to the end
    of the string").

    Can anyone tell me what I need to do to match the final errors in a
    string, and why my second attempt did not work (Is this because
    negating a group of characters in this way does not behave in the way
    you would expect? I cannot find any examples in the docs)?

    Thanks,

    Stephen.
     
    Stephen O'D, Jun 1, 2005
    #1
    1. Advertising

  2. Stephen O'D wrote:
    >
    > I have a variable (two different cases):-
    >
    > my $text = "foo_errors_bar";
    > my $text = "foo_errors_bar_errors_foobar";
    >
    > I need to substitute the final 'errors' out of the string leaving me
    > with:-
    >
    > $text = 'foo__bar';
    > $text = 'foo_errors_bar__foobar';


    $text =~ s/errors(?!.*errors)//;

    --
    Gunnar Hjalmarsson
    Email: http://www.gunnar.cc/cgi-bin/contact.pl
     
    Gunnar Hjalmarsson, Jun 1, 2005
    #2
    1. Advertising

  3. Stephen O'D wrote:

    > I can't believe I cannot get this to work, as it seems so simple, but I
    > am so far stumped.
    >
    > I have a variable (two different cases):-
    >
    > my $text = "foo_errors_bar";
    > my $text = "foo_errors_bar_errors_foobar";
    >
    > I need to substitute the final 'errors' out of the string leaving me
    > with:-
    >
    > $text = 'foo__bar';
    > $text = 'foo_errors_bar__foobar';
    >
    > $text =~ s/errors(.+)$/$1/


    That is more simply written

    $text =~ s/errors//;

    > Does not work, as it grabs the first 'errors'.


    Yes, that is right - the regex engine always returns the first match.

    > $text =~ s/errors([^(?:errors)]+)$/$1/


    The [] is a character class construct so what you are trying here is
    only applicable to single character targets.

    > Which does not work at all (I thought this would translate rougly into
    > english as "find errors followed by one or more not errors to the end
    > of the string").


    The word 'errors' is not a character.

    > Can anyone tell me what I need to do to match the final errors in a
    > string,


    As I said, the regex engine always returns the first match, but it aslo
    likes to return the longest match so you can match everything upto and
    including the last 'errors'.

    $text =~ s/(.*)errors/$1/;

    Alternatively you could use negative lookahead.

    $text =~ s/errors(?!.*errors)//;

    I favour the first method.

    > and why my second attempt did not work (Is this because
    > negating a group of characters in this way does not behave in the way
    > you would expect?


    No, it is because it _does_ behave as I would expect.

    > I cannot find any examples in the docs)?


    Any examples of what?

    I just did a search for the word "last" in perlre and the second hit was
    where it explained that putting a (.*) in front of something will find
    the last match.
     
    Brian McCauley, Jun 1, 2005
    #3
  4. Stephen O'D

    John Guest

    Stephen tried:

    $text =~ s/errors([^(?:errors)]+)$/$1/

    (He thought this would translate rougly into english as
    "find errors followed by one or more not errors to the end
    of the string").

    The (.+) will match any string, even 'errors'

    You could try greedily preserving the beginning of the string:

    $text =~ s/(.*)errors(.+)$/$1$2/;
     
    John, Jun 1, 2005
    #4
  5. Stephen O'D

    Stephen O'D Guest

    Guys,

    Thanks for that - I never thought I could get round the regex engine
    matching the first occurrance by allowing it to match the longest.

    /(.*)errors/$1/

    Seems to be the best solution in the general case.

    In reply to Brian:-

    When i said I could not find any examples in the docs, I was refering
    to negating a group of characters using

    [^(?:errors)]

    Clearly this is because this does not work (now that you explained it
    only applies to single characters) and so it has no place in the docs!

    Thanks for all the help - problem solved!

    Cheers,

    Stephen.
     
    Stephen O'D, Jun 1, 2005
    #5
  6. Stephen O'D <> wrote:

    > I have a variable (two different cases):-
    >
    > my $text = "foo_errors_bar";
    > my $text = "foo_errors_bar_errors_foobar";
    >
    > I need to substitute the final 'errors' out of the string leaving
    > me with:-
    >
    > $text = 'foo__bar';
    > $text = 'foo_errors_bar__foobar';


    If that's all you want I don't think I'd even bother with the
    subsitution operator.

    substr($text, rindex($text, 'errors'), 6) = '';
     
    David K. Wall, Jun 1, 2005
    #6
  7. Stephen O'D

    Anno Siegel Guest

    Stephen O'D <> wrote in comp.lang.perl.misc:
    > Hi,
    >
    > I can't believe I cannot get this to work, as it seems so simple, but I
    > am so far stumped.
    >
    > I have a variable (two different cases):-
    >
    > my $text = "foo_errors_bar";
    > my $text = "foo_errors_bar_errors_foobar";
    >
    > I need to substitute the final 'errors' out of the string leaving me
    > with:-
    >
    > $text = 'foo__bar';
    > $text = 'foo_errors_bar__foobar';
    >
    > $text =~ s/errors(.+)$/$1/
    >
    > Does not work, as it grabs the first 'errors'.


    $_ = do {
    $_ = reverse;
    s/srorre//;
    reverse;
    } for $text;

    Anno
     
    Anno Siegel, Jun 2, 2005
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. news.hku.hk
    Replies:
    7
    Views:
    7,738
    Michiel Salters
    Apr 26, 2004
  2. magix
    Replies:
    3
    Views:
    317
    user923005
    May 21, 2008
  3. Patrick Spence
    Replies:
    2
    Views:
    121
    Patrick Spence
    Aug 19, 2006
  4. Replies:
    2
    Views:
    82
  5. Greg Gallagher
    Replies:
    6
    Views:
    102
    Greg Gallagher
    Nov 19, 2003
Loading...

Share This Page