regex question

J

John Black

How do I write a regex that will match on

string

but not

string_

I want it to match if it detects string followed by anything but an underscore including if
string is at the end of the line or if its followed by a space or whatever. Right now I'm
essentially doing two checks: matches string and does not match string_ but I am sure there
must be a more elegant way to do it? Thanks.

John Black
 
R

Rainer Weikusat

John Black said:
How do I write a regex that will match on

string

but not

string_

I want it to match if it detects string followed by anything but an underscore including if
string is at the end of the line or if its followed by a space or
whatever.

/string(?!_)/
 
J

Jim Gibson

Rainer said:
/string(?!_)/

To elucidate: that is a "zero-width negative look-ahead assertion". For
more information, see 'perldoc perlre' and search or scroll to the
section on "Extended Patterns", specifically the subsection on
"Look-Around Assertions".
 
J

John Black

To elucidate: that is a "zero-width negative look-ahead assertion". For
more information, see 'perldoc perlre' and search or scroll to the
section on "Extended Patterns", specifically the subsection on
"Look-Around Assertions".

This is great. Thanks to both of you. It does work for my example but I tried to apply it
to a different example and its not working. I want to match on some pattern that is not
followed by some other string later but not necessarily immediately following like my
original example.

I tried /pattern1.*(?!string)/

but this seems to match pattern1 even if "string" comes later somewhere on the line.

John Black
 
C

Charles DeRykus


This is great. Thanks to both of you. It does work for my example but I tried to apply it
to a different example and its not working. I want to match on some pattern that is not
followed by some other string later but not necessarily immediately following like my
original example.

I tried /pattern1.*(?!string)/

but this seems to match pattern1 even if "string" comes later somewhere on the line.

Another alternative to lookaheads is the /p switch which effectively
partitions a successful match into pre-match, match, and post-match:

if ( "foo bar" =~ /foo/p and ${^POSTMATCH} !~ /bar/ ) ...

So, ${^PREMATCH} is "", ${^MATCH} is"foo", and ${^POSTMATCH} is " bar"

P.S. ( "p" in /p doesn't mean "partition" but it's still an easy way to
remember what happens. See perlre ).
 
J

John Black


This is great. Thanks to both of you. It does work for my example but I tried to apply it
to a different example and its not working. I want to match on some pattern that is not
followed by some other string later but not necessarily immediately following like my
original example.

I tried /pattern1.*(?!string)/

but this seems to match pattern1 even if "string" comes later somewhere on the line.

Another alternative to lookaheads is the /p switch which effectively
partitions a successful match into pre-match, match, and post-match:

if ( "foo bar" =~ /foo/p and ${^POSTMATCH} !~ /bar/ ) ...

So, ${^PREMATCH} is "", ${^MATCH} is"foo", and ${^POSTMATCH} is " bar"

P.S. ( "p" in /p doesn't mean "partition" but it's still an easy way to
remember what happens. See perlre ).

Charles, thanks. I like it. Its actually more readable than the negative lookahead syntax.

John Black
 
J

John Black

Yes. Think a bit about how it matches. If you match (say)

"foo bar" =~ /foo.*(?!bar)/

then first the 'foo' matches the 'foo', then the .* matches the ' bar',
then perl tries to match /bar/ at that point. It doesn't match (we're at
the end of the string), so the (?!) succeeds, and the whole match
succeeds.

Running a match under 'use re "debug";' might help you to understand
what's going on, though it tends to produce so much output it takes a
bit of practice to sort through it.

You want to assert 'starting immediately after the 'foo', it must not be
possible to match any amount of text followed by 'bar''. That is,

/foo(?!.*bar)/

with the .* inside the (?!). (You may also want /s.)

Ben, thanks. This makes sense but I'm not sure where I would want the /s or why?

John Black
 
J

John Black

Read the section on m// in perlop. /s makes . match newline, which it
otherwise doesn't.

Ah yes. I was confused because for some reason, I saw your /s as \s. Thanks.

John Black
 

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

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,022
Latest member
MaybelleMa

Latest Threads

Top