Matching final occurance of a string in text

S

Stephen O'D

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.
 
G

Gunnar Hjalmarsson

Stephen said:
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)//;
 
B

Brian McCauley

Stephen said:
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.
 
J

John

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/;
 
S

Stephen O'D

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.
 
D

David K. Wall

Stephen O'D said:
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) = '';
 
A

Anno Siegel

Stephen O'D said:
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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,567
Members
45,042
Latest member
icassiem

Latest Threads

Top