Welcome to WebmasterWorld Guest from 184.73.33.127

Forum Moderators: coopster & jatar k & phranque

Message Too Old, No Replies

perl if elsif control flow

skipping to other parts of an if block

     
8:13 pm on Jul 18, 2008 (gmt 0)

Junior Member

10+ Year Member

joined:Nov 11, 2004
posts:84
votes: 0


I have a perl script parsing access logs and have run into a particular problem

if ($ref =~ m/a/) {
$type = "Type A";
} elsif ($ref =~ m/b/) {
$type = "Type B";
} elsif ($ref =~ m/c/) {
$type = "Type C";
} elsif ($ref =~ m/d/) {
$type = "Type D";
}

My problem is I have some referers that will match to b, but really need to be classified as some other Type further down the if block. I tried to use the next statement but that didn't work.

elsif ($ref =~ m/b/) {
if ($ref =~ m/bc/) {
next;
}
$type = "Type B";
}

Then I tried

elsif ($ref =~ m/b/ && $ref !~ m/bc/) {
$type = "Type B";
}

and that skips the b block correctly, but I have something like bcs that needs to be Type C and bcb that needs to be Type B. So I really need to get something similar to what I was trying with the next statement. Any suggestions?

8:16 pm on July 18, 2008 (gmt 0)

Senior Member

WebmasterWorld Senior Member 5+ Year Member

joined:May 31, 2008
posts:661
votes: 0


hm, so /bcs/ should go to C and /bcb/-matches should go to B? is there a general rule for that?
maybe you could go with something like

elsif ($ref =~ m/b/ && $ref !~ m/bc[stmnl]/) {

where stmnl are all the characters that would classify the bc*-thingy as type C?

8:39 pm on July 18, 2008 (gmt 0)

Junior Member

10+ Year Member

joined:Nov 11, 2004
posts:84
votes: 0


I'm really trying to parse out nested URL query strings. I'd prefer not to hardcode them so my pattern is actually more like /xcode=([^&]+)/ The problem with

elsif ($ref =~ m/xcode=b([^&]+)/ && $ref !~ m/xcode=bc[snmtl][^&]+/) {
$type = "Type B";
}

This results in false positives when the URL has file.html?xcode=b&ycode=2&xcode=bcs&zcode=return In this case the first xcode=b supercedes the second xcode=bcs, but I have no guarantee of what order they will be in. I'd like to avoid creating a list of all valid "b" values but that's starting to look like the simplest solution.

9:04 pm on July 18, 2008 (gmt 0)

Senior Member

WebmasterWorld Senior Member 5+ Year Member

joined:May 31, 2008
posts:661
votes: 0


well, couldn't you do a split on it first, than put it into a hash and query that? that way, you wouldn't have to worry about order, you could just check
if($hash{'bc'} && !$hash{'bc'})

I don't completly understand how you want to build a general rule _without_ letting your script know all the valid values for different types...

10:13 pm on July 18, 2008 (gmt 0)

Preferred Member

10+ Year Member

joined:Jan 5, 2006
posts:536
votes: 0


I don't understand what you are trying to do.
1:59 am on July 19, 2008 (gmt 0)

Senior Member

WebmasterWorld Senior Member rocknbil is a WebmasterWorld Top Contributor of All Time 10+ Year Member

joined:Nov 28, 2004
posts:7999
votes: 0


My problem is I have some referers that will match to b, but really need to be classified as some other Type further down the if block.

Note that

1. Presuming you're going through a file (log) in a while loop, next will skip to the next line and ignore any matching on this line completely. So that won't work.

2. if/elsif can catch you in exactly these circumstances. Since you catch the first condition in an elsif, it's gong to ignore anything after. Right?

So, maybe a simple workaround is to not use elsif at all, just a series of if's. You have to use caution when you do this, as later if's will overwrite previous ones, which sounds like what you want to do.

$string = 'aaaabccc';

if ($string =~ /a/) { $letter = 'A'; }
if ($string =~ /b/) { $letter = 'B'; }
if ($string =~ /c/) { $letter = 'C'; }

print $letter;

So at first, $letter is A, but it gets overwritten and becomes B, then in the third match becomes C. You may want more complex if's further down:


if ($string =~ /a/) { $letter = 'A'; }
if ($string =~ /b/) {
$letter = ($string =~ /a/)?'both A and B':'B';
}
if ($string =~ /c/) {
$letter = ($string =~ /[ab]/)?'Contains A or B, and C':'C';
}

As always, TMTOWTDI in Perl. :-)

6:18 am on July 19, 2008 (gmt 0)

Administrator

WebmasterWorld Administrator phranque is a WebmasterWorld Top Contributor of All Time 10+ Year Member Top Contributors Of The Month

joined:Aug 10, 2004
posts:10682
votes: 33


as a rule you should put your most specific tests first and the more general tests later.
 

Join The Conversation

Moderators and Top Contributors

Hot Threads This Week

Featured Threads

Free SEO Tools

Hire Expert Members