CGI/Perl Guide | Learning Center | Forums | Advertise | Login
Site Search: in

  Main Index MAIN
INDEX
Search Posts SEARCH
POSTS
Who's Online WHO'S
ONLINE
Log in LOG
IN

Home: Fun With Perl: Perl Quizzes - Learn Perl the Fun Way:
regular expression tomfoolery

 



japhy
Enthusiast

Jul 16, 2000, 9:33 AM

Post #1 of 9 (16180 views)
regular expression tomfoolery Can't Post

Correct the following regular expression:

<BLOCKQUOTE><font size="1" face="Arial,Helvetica,sans serif">code:</font><HR>


@str = qw( foobar candybar );
for (@str) {
print if /(?!foo)bar/;
}
</pre><HR></BLOCKQUOTE>

The aim of the code is to match 'bar' that is NOT directly preceeded by 'foo'.

Try and make a solution that doesn't use ANY special regex features (the (?!...) and (?=...) stuff). The ONLY exception is (?:...).

Hint: "unrolling the loop" from "Mastering Regular Expressions"

[This message has been edited by japhy (edited 07-16-2000).]


Kanji
User / Moderator

Jul 15, 2000, 10:31 PM

Post #2 of 9 (16180 views)
Re: regular expression tomfoolery [In reply to] Can't Post

print if /bar/ and not /foobar/;
print if /bar/ and $` !~ /foo$/;
print if /([^f][^o][^o]|\b)bar/;


dws
Deleted

Jul 16, 2000, 2:26 PM

Post #3 of 9 (16180 views)
Re: regular expression tomfoolery [In reply to] Can't Post

<BLOCKQUOTE><font size="1" face="Arial,Helvetica,sans serif">code:</font><HR>

@str = qw( foobar candybar );
for (@str) {
next if /foobar/;
print if /foo/;
}
</pre><HR></BLOCKQUOTE>



japhy
Enthusiast

Jul 16, 2000, 2:53 PM

Post #4 of 9 (16180 views)
Re: regular expression tomfoolery [In reply to] Can't Post

Ok, a slight modification to my quiz...

Can you get it done with a SINGLE regex?

Also, Kanji:

<BLOCKQUOTE><font size="1" face="Arial,Helvetica,sans serif">code:</font><HR>


print if /([^f][^o][^o]|\b)bar/;
</pre><HR></BLOCKQUOTE>

doesn't work on strings like "abar", since the /[^f][^o][^o]/ matches "aba". It also doesn't work on strings like "boobar", since /[^f][^o][^o]/ can't match "boo".


dws
Deleted

Jul 16, 2000, 9:21 PM

Post #5 of 9 (16180 views)
Re: regular expression tomfoolery [In reply to] Can't Post

I assume that a correct solution handles cases where both foobar and a non-foo-prefixed bar appear in the same input string.
<BLOCKQUOTE><font size="1" face="Arial,Helvetica,sans serif">code:</font><HR>

@str = qw( foobar candybar );
for (@str) {
my @prefix = /(^|^.|^..|...)bar/g;
print if 0 < grep { $_ ne "foo" } @prefix;
}
</pre><HR></BLOCKQUOTE>


[This message has been edited by dws (edited 07-16-2000).]


japhy
Enthusiast

Jul 17, 2000, 5:26 AM

Post #6 of 9 (16180 views)
Re: regular expression tomfoolery [In reply to] Can't Post

If the string is "okbar and foobar", the string should not match.

The aim of this regex is to make sure a substring is not immediately preceeded by another substring. This can be done simply for constant-length substrings by saying:

<BLOCKQUOTE><font size="1" face="Arial,Helvetica,sans serif">code:</font><HR>


/(?<!foo)bar/
</pre><HR></BLOCKQUOTE>

But the negative look-behind assertion (?!<...) was explicitly forbidden by me. Smile

As for your latest response DWS...

<BLOCKQUOTE><font size="1" face="Arial,Helvetica,sans serif">code:</font><HR>


@str = qw( foobar candybar );
for (@str) {
# XXX: allow for \n by adding the /s modifier
my @prefix = /(^|^.|^..|...)bar/g;
# XXX: this should be: if 0 == grep $_ eq "foo", @prefix;
print if 0 < grep { $_ ne "foo" } @prefix;
}
</pre><HR></BLOCKQUOTE>

The desired result of the code is, given the following strings, the ones marked with * pass through unscathed.

<BLOCKQUOTE><font size="1" face="Arial,Helvetica,sans serif">code:</font><HR>


no foo bar*
foobar
fobar*
fofobar*
fooobar*
somebar foobar
foobar somebar
otherbar*
</pre><HR></BLOCKQUOTE>

I was really giving a hint when I mentioned the "unrolling the loop" technique. Think of how a valid string (one that passes) must be formed.


dws
Deleted

Jul 17, 2000, 9:12 AM

Post #7 of 9 (16180 views)
Re: regular expression tomfoolery [In reply to] Can't Post

"The aim of the code is to match 'bar' that is NOT directly preceeded by 'foo'."

A strict read of this says that the string "okbar and foobar" should match, based on the first 'bar'. And the loop unrolling hint does not suggest otherwise. And if all you want to do is reject any line containing "foobar", then

next if /foobar/;

is sufficient. That's hardly interesting.

(Didn't expect this to become a side lesson in requirements analysis, did you? :-)

This might be more along the lines of what you're looking for:
<BLOCKQUOTE><font size="1" face="Arial,Helvetica,sans serif">code:</font><HR>

@str = ("no foo bar", "foobar", "fobar",
"fofobar", "fooobar", "somebar foobar",
"foobar somebar", "otherbar");
for ( @str ) {
print;
print "*" if /(^.{0,2}bar|f[^o]obar|fo[^o]bar|[a-eg-z]..bar)/i;
print "\n";
}
</pre><HR></BLOCKQUOTE>


[This message has been edited by dws (edited 07-17-2000).]


japhy
Enthusiast

Jul 17, 2000, 7:58 PM

Post #8 of 9 (16180 views)
Re: regular expression tomfoolery [In reply to] Can't Post

Ok, I see where you're coming from, dws. What I intended this to mean is "if the string has a 'bar', then it's a match, UNLESS it is preceeded by 'foo', then it is NOT a match.

Here is my solution. A successful string will be able to match as follows:

<BLOCKQUOTE><font size="1" face="Arial,Helvetica,sans serif">code:</font><HR>


m{
^ # start of string
[^f]* # 0 or more non-f's
(?: # followed by
f+ # 1 or more f's
(?: # followed by
o? [^o] # 0 or 1 o followed by a non-o
| # or
ooo+ # 3 or more o's
)
[^f]* # followed by 0 or more non-f's
)* # the non-foo part 0 or more times
bar # followed by 'bar'
}x
</pre><HR></BLOCKQUOTE>


wuntvor
Deleted

Jul 31, 2000, 1:34 PM

Post #9 of 9 (16180 views)
Re: regular expression tomfoolery [In reply to] Can't Post

what about the following:
#!/usr/bin/perl

@str = qw(foobar crowbar candybar foobar);
for (@str)
{
print if (/(foo)*bar/ && ! $1);
}

 
 


Search for (options) Powered by Gossamer Forum v.1.2.0

Web Applications & Managed Hosting Powered by Gossamer Threads
Visit our Mailing List Archives