Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

matching a high range of numbers. 3

Status
Not open for further replies.

exsnafu

Technical User
Apr 25, 2008
99
0
0
US
I need to match numbers 200-220 in a string, this seems pretty simple but i'm having a hard time getting it to match exactly those numbers.. matching 200-219 i can do but matching up to 220 but not 221 im struggling with.

sample:
#!/usr/bin/perl

my $var = $ARGV[0];

if ( $var =~ /2[0-1][0-9]/ ) { print "$var\n"; }

but for matching up to 220 isnt really working for me, can someone point me in the right direction?
 
Hi

Regular expressions are for string manipulations. Checking numeric/date/time values is not really their job.
Code:
[b]if[/b] [teal]([/teal] [navy]$var[/navy] [teal]=~[/teal] [green][i]/2[0-1][0-9]|220/[/i][/green] [teal])[/teal] [teal]{[/teal] [b]print[/b] [green][i]"$var\n"[/i][/green][teal];[/teal] [teal]}[/teal]

[gray]# or[/gray]

[b]if[/b] [teal]([/teal] [navy]$var[/navy] [teal]=~[/teal] [green][i]/2([0-1][0-9]|20)/[/i][/green] [teal])[/teal] [teal]{[/teal] [b]print[/b] [green][i]"$var\n"[/i][/green][teal];[/teal] [teal]}[/teal]

[gray]# or[/gray]

[b]if[/b] [teal]([/teal] [navy]$var[/navy] [teal]=~[/teal] [green][i]/2([0-1][0-9]|20)/[/i][/green] [teal]&&[/teal] [teal]([/teal]$[teal]&==[/teal][purple]200[/purple][teal]..[/teal]$[teal]&==[/teal][purple]220[/purple][teal])[/teal] [teal])[/teal] [teal]{[/teal] [b]print[/b] [green][i]"$var\n"[/i][/green][teal];[/teal] [teal]}[/teal]

[gray]# or[/gray]

[b]if[/b] [teal]([/teal] [navy]$var[/navy][teal]==[/teal][purple]200[/purple][teal]..[/teal][navy]$var[/navy][teal]==[/teal][purple]220[/purple] [teal])[/teal] [teal]{[/teal] [b]print[/b] [green][i]"$var\n"[/i][/green][teal];[/teal] [teal]}[/teal]

Feherke.
 
thanks feherke, i suppose i was assuming there was a more elegant solution available out there but maybe not...

incidently i'm not sure some of those possible solutions really work? for instance the problem i have with using [] ranges is that it'll match 200, 2000, 200000 etc and the last one doesnt work at all, for me anyways.. it'll match 200 but nothing else.
 
I think I got it working just the way I wanted....

Code:
if ( $var =~ /(?:2[0-1]{1}[0-9]{1}|20)$/ ) { print "$var\n"; }
 
also just so people don't think i'm being silly for not using a simple numerical comparison, the actual problem is more complex as i'm trying to match on a set of numbers inside of a larger string and rather than extract that one piece of the string to do a comparison on i was wondering if i could integrate it altogether.
 
exsnafu, using the regex you ended up with in the below code gives 498 results not just the 21 (200-220) you're looking for.)

Code:
my @arr = 0..10000;
$\ = "\n";
foreach (@arr) {
	print if /(?:2[0-1]{1}[0-9]{1}|20)/;
}
Using the same code, this regex gives the expected 200-220 results.
Code:
print if m/(?<!\d)2(?(?=2)20|[01][0-9])(?!\d)/;
 
rharsh, your last regex matches 231 times in that range, including, as an example, 2189!
Why not this one? It is easier to understand, manipulate and adapt to a different range, for the least. It also captures multiple occurrences in the same string. However, exsnafu, notice that it will also match on a string like -205.25
Code:
while(/\b(\d{3})\b/g&&$1>=200&&$1<=220){
  print$1,"\n";
}

Franco
: Online engineering calculations
: Magnetic brakes for fun rides
: Air bearing pads
 
Franco, that's interesting... using activeperl 5.8.8 (817):
Code:
D:\>perl -i
@arr = 0..10000;
for (@arr) {
        print "$_\n" if m/(?<!\d)2(?(?=2)20|[01][0-9])(?!\d)/;
}
^Z
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220

D:\>
If it's matching 231 times, my guess is the negative look-ahead is not working the way I would expect. It could be the negative look-behind isn't working either. Do you know if, just picking one at random, 1200 was printed as well? Out of curiosity, what version of perl are you running?

Also, it could be problematic using \b, if the number is embedded within other \w characters (for example a200 or 220m) using \b will not match. The OP would have to give a better example of the strings that the regex needs to match against.
 
Any reason you can't just extract the digits as $1 using a regex, then do a range check on them? I know this may offend the regex purists but it's simple and gets the job done...

Steve

[small]"Every program can be reduced by one instruction, and every program has at least one bug. Therefore, any program can be reduced to one instruction which doesn't work." (Object::perlDesignPatterns)[/small]
 
Using activeperl 5.10.0
1200 is not included: besides the correct 200..220 range, it finds 4 (or more) figure numbers whose first 3 figures are in the range 200..220.
If the numbers to find may be embedded in words, we change to
Code:
while(/\b\D*(\d{3})\D*\b/g&&$1>=200&&$1<=220){
  print$1,"\n";
}
Still this will match -205.25; also it won't match on two (or more) accepted numbers that would be embedded in the same word.

Franco
: Online engineering calculations
: Magnetic brakes for fun rides
: Air bearing pads
 
so, rharsh' regex works perfectly for me(on aix perl 5.8.3), i get just the expected 200-220 results.

thanks a lot guys, i really appreciate this kind of feedback..

and steve: there isn't really any reason except maybe speed? i actually started out doing it the other way but i figure(maybe incorrectly) that its more streamlined this way and plus im trying to get a better feel for perl regex. :)

Code:
[9126][vioc01-12]:/home/jeff> perl -e '@n = 0..99999;for (@n) { print "$_\n" if m/(?<!\d)2(?(?=2)20|[01][0-9])(?!\d)/; }'
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
[9127][vioc01-12]:/home/jeff>


again, greatly appreciated the different options.
 
You'd probably have to benchmark it - complex regexes can soak up a lot of CPU, while a simpler regex coupled with a simple range check could be cheaper...

Steve

[small]"Every program can be reduced by one instruction, and every program has at least one bug. Therefore, any program can be reduced to one instruction which doesn't work." (Object::perlDesignPatterns)[/small]
 
Without benchmarking the two methods, I'd guess Franco's code is faster (and easier to understand.)
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top