Re: Regexp for range of numbers
by gellyfish (Monsignor) on Apr 05, 2005 at 09:02 UTC
|
I'm sure you have your reasons for wanting to do this with a regular expression , but surely the smart way to do it would be:
$number >= 0 and $number <= 255
numeric comparison is going to be faster as that is something that computers can do natively.
/J\ | [reply] [d/l] |
|
|
| [reply] |
Re: Regexp for range of numbers
by Corion (Patriarch) on Apr 05, 2005 at 09:06 UTC
|
Of course, with 5.9.2, there is a much nicer way to construct an efficient regular expression to match the numbers from 0 to 255 without leading zeroes:
use strict;
my $zero_to_255 = join "|", 0..255;
$zero_to_255 = qr(^(?:$zero_to_255)$);
print $zero_to_255,"\n";
for (-2,-1, 0..259) {
print "$_\n"
unless /$zero_to_255/;
};
| [reply] [d/l] |
|
|
So, stringing together a somewhat large number of static ORs in a regular expression is efficient? - Programmer wise, I agree.
- Space wise, not so much.
- Time wise? If it is, it is counter intuitive to me...
-Scott
| [reply] |
|
|
Please note that I mentioned 5.9.2, the most current release of the developer branch, which has a patch by demerphq, that builds a very optimized tree out of a list like mine. The tree (actually a Trie) can the optimally match/compare against the string, by looking at exactly the first three chars of the string and quickly decide if it matches or not.
| [reply] |
|
|
|
|
|
Re: Regexp for range of numbers
by reneeb (Chaplain) on Apr 05, 2005 at 09:17 UTC
|
Regexp::Assemble shows
(?-xism:^(?:2(?:[6789]|5[012345]?|[01234]\d?)?|[3456789]\d?|1(?:\d\d?)?|0)$) as the RegExp for your problem... | [reply] [d/l] |
Re: Regexp for range of numbers
by deibyz (Hermit) on Apr 05, 2005 at 10:10 UTC
|
TIMTOWTDI, and I wanted to play with (?(condition)true-pattern|false-pattern) asserts.
Looks like this:
my $re =qr/
^(\d{1,3})$ # Up to 3 digits
(?(?{ ($1<256 and $1>=0) }) # If in the correct range
.? # An allways match
| # Else
. # Never going to match after e
+nd of string
)
/x;
| [reply] [d/l] [select] |
|
|
You don't need to test against zero. Or put anything in the success-pattern; an empty pattern matches just fine.
/^(\d{1,3})$(?(?{$1<256 }) | . )/x
or you could move your anchor and use an impossible anchor for the fail-pattern:
/^(\d{1,3})(?(?{$1<256 }) $ | ^ )/x
Caution: Contents may have been coded under pressure.
| [reply] [d/l] [select] |
|
|
I tend to use (?!) for the always fail pattern (there are no positions that aren't followed by the empty string). ^ might match if a /m flag is in use, or if the zero-width assertion is done at the beginning of the string. An empty string works fine as an always match pattern - or (?=) if you want to go symmetric.
| [reply] [d/l] [select] |
Re: Regexp for range of numbers
by simon.proctor (Vicar) on Apr 05, 2005 at 09:14 UTC
|
To repeat a node above, doing this with regex seems a little odd. Anyway, I thought I would take 5 and have a go. I did mine with look behinds (cos I rarely get to use them and its different to your solution). Not sure if my attempt is bone headed :). Still . . . here it is:
use strict;
use warnings;
my @nums;
for(my $i = -100; $i < 400; $i++)
{
push @nums, $i;
}
foreach my $n (@nums)
{
if($n =~ /^[012]?(((?<=2)[0-5])|(?<!2)[0-9])?(((?<=25)[0-5])|(?<!2
+5)[0-9])$/)
{
print $n, ": pass\n";
}
else
{
print $n, ": fail\n";
}
}
HTH | [reply] [d/l] |
Re: Regexp for range of numbers
by Roy Johnson (Monsignor) on Apr 05, 2005 at 11:03 UTC
|
Update: Don't use this. $1 comes from the previous match, not the current one. You would have to use experimental features for a solution in this vein.
This reads a little nicer, but I don't know whether you'd consider it cheating. It's a Perl regex:
/^(\d{1,3})${\($1 > 255 ? qr(^) : qr($))}/
Three digits, then interpolate a scalar ref block that tests what has already matched and returns the rest of the regexp: if the number is too high, the pattern is impossible; otherwise, end-of-string.
Update: meant to link to the post, not the poster. So now "solutions in this vein" links to the post.
Caution: Contents may have been coded under pressure.
| [reply] [d/l] |
|
|
Hey! I've just noticed you're calling me "experimental feature".
Thanks!! =oD
| [reply] |
|
|
That doesn't work. Interpolation happens before the regex is performed, so your $1 refers to a previous succesful match:
#!/usr/bin/perl
use strict;
use warnings;
while (<DATA>) {
chomp;
printf "%d %s\n", $_, /^(\d{1,3})${\($1 > 255 ? qr(^) : qr($))}/
? "matches" : "fails";
}
__DATA__
3
100
333
200
Use of uninitialized value in numeric gt (>) at XXX line 9, <DATA> lin
+e 1.
3 matches
100 matches
333 matches
200 fails
| [reply] [d/l] |
|
|
| [reply] |
|
|
|
|
Re: Regexp for range of numbers
by Roy Johnson (Monsignor) on Apr 05, 2005 at 12:10 UTC
|
My previous answer is wrong, because variables are interpolated at the time the regex is created. This relatively compact expression works, though:
use strict;
use warnings;
my @nums = (100,-3,150,-2,-1,256, 280, 254);;
foreach my $n (@nums)
{
print "$n: ",
($n !~ /^1?\d{1,2}$|^2(?:[0-4]\d|5[0-5])$/)
? 'fail' : 'pass';
}
Caution: Contents may have been coded under pressure.
| [reply] [d/l] |
|
|
| [reply] [d/l] [select] |