For Programmers: Free Programming Magazines  


Home > Archive > PERL Miscellaneous > March 2004 > Regex match for one and only one occurrence of a pattern









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author Regex match for one and only one occurrence of a pattern
Steve Allgood

2004-03-28, 10:22 pm

I'm trying to match one and only one occurrence of a pattern in a string.

For example, for the pattern 'bc' I want a regex to match 'abcd' but not 'abcdabcd'.

I have tried /bc(?!(.*bc)+)/ but that doesn't work. It just matches the last 'bc'.

Any suggestions?

Thanks,
Steve
Tad McClellan

2004-03-29, 1:31 am

Steve Allgood <chiriones@yahoo.com> wrote:
> I'm trying to match one and only one occurrence of a pattern in a string.
>
> For example, for the pattern 'bc' I want a regex to match 'abcd' but not 'abcdabcd'.
>
> I have tried /bc(?!(.*bc)+)/ but that doesn't work. It just matches the last 'bc'.
>
> Any suggestions?



print "matched\n" if s/bc/bc/g == 1;


--
Tad McClellan SGML consulting
tadmc@augustmail.com Perl programming
Fort Worth, Texas
Brian McCauley

2004-03-29, 7:34 am

Tad McClellan <tadmc@augustmail.com> writes:

> Steve Allgood <chiriones@yahoo.com> wrote:
>
>
> print "matched\n" if s/bc/bc/g == 1;


Nice, but using s/// to not modify a string makes me feel a little
uncomfortable.

print "matched\n" if (() = /bc/g) == 1;

Note: The above only works for regex with no captures.

Or..

# Assume pos() == 0 initially
print "matched\n" if /bc/g && ! /bc/g;
# Warning: maybe pos() != 0 now


Or rather more directly...

print "matched\n" if /bc/ && !/bc.*bc/;

Of course if you must do it in one regex:

print "matched\n" if /^(?!(.*bc){2}).*bc/;

However if you are compelled to use a single regex because you are
calling a function that takes a regex argument you may want to alter
that function to accept coderef arguments too.

--
\\ ( )
. _\\__[oo
.__/ \\ /\@
. l___\\
# ll l\\
###LL LL\\
Tad McClellan

2004-03-29, 9:45 am

Brian McCauley <nobull@mail.com> wrote:
> Tad McClellan <tadmc@augustmail.com> writes:
>
[color=darkred]

[color=darkred]
>
> Nice, but using s/// to not modify a string makes me feel a little
> uncomfortable.
>
> print "matched\n" if (() = /bc/g) == 1;



I had that one too, but I felt it had too much "startle factor" to post.


> Or..
>
> # Assume pos() == 0 initially
> print "matched\n" if /bc/g && ! /bc/g;
> # Warning: maybe pos() != 0 now
>
>
> Or rather more directly...
>
> print "matched\n" if /bc/ && !/bc.*bc/;
>
> Of course if you must do it in one regex:
>
> print "matched\n" if /^(?!(.*bc){2}).*bc/;



I gave The Way I did because the alternatives fell victim to:

it doesn't pass the 'just read it aloud' test

(some good advice that I was given here recently)


Now the pendulum swings the other way. :-)


--
Tad McClellan SGML consulting
tadmc@augustmail.com Perl programming
Fort Worth, Texas
Richard Morse

2004-03-29, 3:36 pm

In article <e33c37bb.0403281853.2e6a0156@posting.google.com>,
chiriones@yahoo.com (Steve Allgood) wrote:

> I'm trying to match one and only one occurrence of a pattern in a string.
>
> For example, for the pattern 'bc' I want a regex to match 'abcd' but not
> 'abcdabcd'.
>
> I have tried /bc(?!(.*bc)+)/ but that doesn't work. It just matches the last
> 'bc'.


Well, you have the negative look-ahead, so maybe you need a negative
look-behind?

You'll have to play around with this a bit, as this is completely
untested...

print "matched" if m/(?<!bc.*)bc(?!.*bc)/;

HTH,
Ricky
Paul Lalli

2004-03-29, 4:34 pm

On Mon, 29 Mar 2004, Richard Morse wrote:

> In article <e33c37bb.0403281853.2e6a0156@posting.google.com>,
> chiriones@yahoo.com (Steve Allgood) wrote:
>
>
> Well, you have the negative look-ahead, so maybe you need a negative
> look-behind?
>
> You'll have to play around with this a bit, as this is completely
> untested...
>
> print "matched" if m/(?<!bc.*)bc(?!.*bc)/;
>


I think that'll cause a regexp error, as lookbehind assertions must be
fixed-width

Move the .* out of the assertion:

print "matched" if m/(?<!bc).*bc.*(?!bc)/;

The .* is allowable in the lookahead, of course. I just moved it out for
symmetry's sake.


Paul Lalli
Steven Kuo

2004-03-29, 4:34 pm

On 28 Mar 2004, Steve Allgood wrote:

> I'm trying to match one and only one occurrence of a pattern in a
> string.
>
> For example, for the pattern 'bc' I want a regex to match 'abcd'
> but not 'abcdabcd'.
>
> I have tried /bc(?!(.*bc)+)/ but that doesn't work. It just
> matches the last 'bc'.
>
> Any suggestions?
>
> Thanks,
> Steve




One way:

if ( @{[ m/bc/g ]} == 1 ) {

# matched just once

}

--
Hope this helps,
Steven

Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2008 codecomments.com