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: Perl Programming Help: Regular Expressions:
Using ? : inside RegExp

 



LeoF
Novice

Sep 8, 2000, 11:21 PM

Post #1 of 4 (2514 views)
Using ? : inside RegExp Can't Post

Hello everyone,

Could someone be so kind as to help me with this? I'm working on modifying a smilies sub routine for a bulletin board, I would like for it to do the conversion to the IMG tag if and only if that image file exists, otherwise leave it untouched. Here is what I tried:

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


$avl_smilies = "smile bigsmile laugh wink mad cool rolling tongue sad cry afraid";
#
$test = "Testing testing :smile: testing testing :mad: testing testing :cool:";
#
#if I try this it will always go to the else part
$test =~ s,(\ Smile(\S+?)(\ Smile,$2 =~ $avl_smilies ? <IMG SRC=\"/graphics/ $2.gif\"> : $2,isge;
#
#if I try this I get:
# Testing testing IMG testing testing SRC=/graphics/.gif testing testing :cool:
$test =~ s,(\ Smile(\S+?)(\ Smile, $avl_smilies =~ $2 ? <IMG SRC=\"/graphics/$2.gif\"> : $2,isge;
</pre><HR></BLOCKQUOTE>

It seems as if $2 is being modified but I don't know where, then I tried:

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

@avl_smilies = qw(smile bigsmile laugh wink mad cool rolling tongue sad cry afraid);
#
$test =~ m,(\ Smile(\S+?)(\ Smile,is;
foreach (@avl_smilies) {
if ($2 eq $_) {
$test =~ s,(\ Smile(\S+?)(\ Smile,<IMG SRC=\"/graphics/ $2.gif\" ALT=\" \">,is;
last;
}
}</pre><HR></BLOCKQUOTE>

and it works as intended but does it only for the first occurrence of a smilie, and I think is very inefficient.

Also if I try:

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

$test =~ s,(\ Smile(\S+?)(\ Smile,$2 =~ $avl_smilies ? <IMG SRC=\"/graphics/ $2.gif\"> : \:$2\:,isge;</pre><HR></BLOCKQUOTE>

To leave the original value as it was, I get an error message.

I've been working on this for so many hours that I don't know what else to try, and I don't even know where the error is coming from.

Any comments and suggestions would be very appreciated.

Thanks in advance for your cooperation.

Be Well



Kanji
User / Moderator

Sep 9, 2000, 4:43 AM

Post #2 of 4 (2514 views)
Re: Using ? : inside RegExp [In reply to] Can't Post

Several things ...

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

$2 =~ $avl_smilies</pre><HR></BLOCKQUOTE>

Unless you only have one available smile, this is never going to match because the comparison is the inverse of what it should be ($avl_smilies may contain $2, but $2 won't usually contain $avl_smiles).

Even inverted, the search has problems because 'big' will actually match 'bigsmile', so you'll want to use a pattern instead and anchor it (/\b$pattern\b/).

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

s,(\ :)(\S+?)(\ :), [..] ? <img [..]> : $2</pre><HR></BLOCKQUOTE>

... won't leave :smile: untouched, but rather change it to smile (sans :'s). You can get around that by either replacing it with ":$2:" and/or by altering your regegp to save the entirety of the original match.

It also won't catch any :smiles: at the start or the end of a string as you embed whitespace in the pattern.

The "Testing testing IMG testing testing SRC=/graphics/.gif" is actually a good trick as it appears perl is treating your everything inside <> as an array and selecting the element corresponding to match number. (ie, $array[$match_no - 1]).

I'll have to play more to see if that's a bug or a feature, but you'll want to escape the entire string for your purposes.

<BLOCKQUOTE><font size="1" face="Arial,Helvetica,sans serif">quote:</font><HR>It seems as if $2 is being modified but I don't know where<HR></BLOCKQUOTE>

See above code for the where. :-)

Everytime you do a match, you reset $1, $2, etc. so while it's available for the search, it's not available anywhere after unless you explicitly save it to $2 again with parenthesis.

Solution? Assign $2 to a temporary variable inside the substitution ...

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

$test =~ s{(:(\S+?):)}{
my($original,$smile) = ($1,$2);
$avl_smilies =~ /\b$smile\b/
? qq(<IMG SRC="/graphics/$smile.gif"> )
: $original;
}isgex;</pre><HR></BLOCKQUOTE>

$original will be :smile:.
$smile will be smile.

HTH!

[This message has been edited by Kanji (edited 09-09-2000).]


japhy
Enthusiast / Moderator

Sep 9, 2000, 6:21 AM

Post #3 of 4 (2514 views)
Re: Using ? : inside RegExp [In reply to] Can't Post

Heh, what a horrible thing for Perl to do. The main problem is you forgot to put quotes around the <IMG SRC=...> text in the regular expression.

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


$test =~ s,(\ Smile(\S+?)(\ Smile, $avl_smilies =~ $2 ? <IMG SRC=\"/graphics/$2.gif\"> : $2,isge;

# should be

$test =~ s,(\ Smile(\S+?)(\ Smile, $avl_smilies =~ $2 ? qq[<IMG SRC="/graphics/$2.gif">] : $2,isge;
</pre><HR></BLOCKQUOTE>

Now that you know that, your probably DYING to know why

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


print <IMG SRC=\"/graphics/$2.gif\">;
</pre><HR></BLOCKQUOTE>

is not a syntax error. Well <> is both the readline() operator for files, and the glob() operator for shell file-globs. Perl thinks you're using <IMG SRC...> as a file glob here, and it does something annoying in this case. Try this:

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


for $x (<what did Perl do?> ) {
print "$x ";
}
</pre><HR></BLOCKQUOTE>

It prints 'what did Perl '. It doesn't print 'do?'. This is because (as far as I've seen) if Perl gets an argument to glob that isn't globbish, it just returns it. 'do?' is globbish, and matches a file that is three characters long and starts with 'do'. But the others just get returned. It's an icky 'feature' that bit you.

Anyway, I'd rewrite the code (slightly) to use a hash instead:

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


%icons = ();
@icons{qw( smile bigsmile ... )} = ();
s! Frown[^:]+):! exists $icons{lc $1} ? qq[<img src="icons/\L$1\E.jpg">] : $1!ge;
</pre><HR></BLOCKQUOTE>

------------------
Jeff "japhy" Pinyan -- accomplished author, consultant, hacker, and teacher



LeoF
Novice

Sep 9, 2000, 11:20 AM

Post #4 of 4 (2514 views)
Re: Using ? : inside RegExp [In reply to] Can't Post

Thanks a lot Kanji and Jeff for helping me understand this 'feature' of Perl, I appreciate it

Thanks for the rewrite Jeff, I'm starting to get the hang of those data structures. I just did a tiny modification to preserve the original and add alt tags:

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

s! Frown[^:]+):! exists $avl_smilies{lc $1} ? qq[<img src="graphics/\L$1\E.gif" alt="\L$1\E">] : ":$1:"!ge;</pre><HR></BLOCKQUOTE>

Is there a way to have the else part not do anything?

Thank you both for your time and attention, I really appreciate it.

Be Well

 
 


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

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