Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options

matching numeric range

by state-o-dis-array (Hermit)
on Feb 24, 2005 at 21:56 UTC ( #434275=perlquestion: print w/replies, xml ) Need Help??
state-o-dis-array has asked for the wisdom of the Perl Monks concerning the following question:

Greetings all,
Well, some help that merlyn supplied in the past encouraged me to use map and some regex magic (magic to me, I'm sure basics to everyone else) to solve a problem, everything worked exactly as I hoped until I tried to match a numeric range - doh! can't regex a numeric range. Here's what I have, I've transformed my data and am working with it in this form: A1:123:C and I need to see if it matches any of an array of data in the form A0-7:123:C where 0-7 is a range. What I would like to know is if there is a way to match the :123:C from each expression, and if so, send the test case and match off to a sub to check for a range match of the A1 to A0-7 portion. I could do
my @array = (A0-7:123:C, B8-15:456:D); my $check = A4:123:C; foreach my $line(@array){ my $subline = join(":", (split(":", $line))[1,2]); #not sure is that join/split thing works just consider this whateve +r it takes to get the 123:C into $subline my $subcheck = #again whatever it takes to get 123:C if ($subcheck =~ /$subline/){ $match = &checkRange($check, $line); } }
I'm looking for something more efficient, though. I have to test about 20-40 cases against 30-40 possible matches, and do this about 400 times, in a somewhat time sensitive environment, so effiency is key.

UPDATE: I'm not looking for the sub to determine if some number is in the range, I can do that. I'm wondering if there is a better approach than the code that I've listed?

Well, I finally got as close to what I wanted to do as I think I'm going to get. I had to take care of a little tunnel vision, that I fear a shared with you in the way I presented my problem, but here is what I came up with:
my @array = (A0-7:123:C, B8-15:456:D); my $check = A4:123:C; my $test = join(' ', @array); my $find = join(':', ((split(':',$check))[1,2])); my @found = ($test =~ m/\b\w\d+\-\d+:$find\b/g);
This way I still have my $check value, and a possible match in @found, and I can send these to a sub to check if the A4 part is in the range of the A0-7 part of the matching value. Thanks to those who were part of my problem solving process.

Replies are listed 'Best First'.
Re: matching numeric range
by jimbojones (Friar) on Feb 24, 2005 at 22:44 UTC

    I think a hash is the answer. Assuming the second 2 elements of your data (delimited by the ':') don't involve the range, you could do something like:

    my %checks = ( '123:C' => [ 'A[0-7]' ], '456:D' => [ 'B[8-9]', 'B1[0-5]' ] ); while ( <DATA>) { chomp; my $check = $_; my $matches = 0; #-- get the trailing key my $first_part = ""; my $key = ""; if ( $check =~ /(\w+):(\w+:\w+)$/ ) { $first_part = $1; $key = $2; } #-- look up key in our checks hash foreach my $match_pattern ( @{$checks{$key}} ) { if ( $first_part =~ /$match_pattern/ ) { print "Line $_ matches $match_pattern:$key\n"; $matches = 1; } } print "Line $_ doesn't match\n" unless ( $matches ); } __DATA__ A4:123:C B8:456:D B11:456:D X11:456:D
    Line A4:123:C matches A[0-7]:123:C Line B8:456:D matches B[8-9]:456:D Line B11:456:D matches B1[0-5]:456:D Line X11:456:D doesn't match

      I'm liking this. One question on this. Is there a simple way (one line regex substitution for example) to get from B10-15 to B1[0-5], or B120-125 to B12[0-5]? Actually, as I think about it, I may need to apply some logic to handle B18-24. Can you think of a good way to handle this one?

        the B10-15 example is easy: B1[0-5] (character class), as is B120-125 (B12[0-5]). As you say, logic spanning B18-24 is more difficult; that's why I broke it into 2 regexs in my post above. It was easier to match B1[8-9] or B2[0-4] than to try some regex-fu. You may be more adept with regexes than I am.

        - j

        update: escape out [ ] so they're visible.

Re: matching numeric range
by esskar (Deacon) on Feb 24, 2005 at 22:21 UTC
    i give it a try
    use strict; my @check = ('A4:123:C'); my @ranges = ('A0-7:123:C', 'B8-15:456:D', 'A5-7:123:C'); foreach my $check (@check) { my @cp = $check =~ m!(\w)(\d+):(\d+):(\w)!; foreach my $range (@ranges) { if($range =~ m!$cp[0](\d+)\-(\d+):$cp[2]:$cp[3]!) { if($check[0] >= $1 and $check[0] <= $2) { print "$check mathes $range\n"; } } } }
      This is probably closer to what I am looking for, thanks esskar, I have to play with the my @cp = $check =~ m!(\w)(\d+):(\d+):(\w)!; line, I've never done something like that.
Re: matching numeric range
by Roy Johnson (Monsignor) on Feb 24, 2005 at 22:19 UTC
    I'm a little unclear about the specifics of your question, but I think the information you're looking for is in this little example program:
    use strict; use warnings; my $range_spec = 'A8-15'; # Parse the range spec: my ($tag, $lo, $hi) = $range_spec =~ /(\D+)(\d+)-(\d+)/; # Check the data lines while (<DATA>) { chomp; my ($dtag, $dnum) = /(\D+)(\d+)/; if ($dtag eq $tag and $dnum >= $lo and $dnum <= $hi) { print "$_ matches $range_spec!\n"; } else { print "Mismatch: $_\n"; } } __DATA__ A1 A2 B8 B11 A11 A9 A15 A16

    Caution: Contents may have been coded under pressure.
Re: matching numeric range
by sh1tn (Priest) on Feb 24, 2005 at 22:43 UTC
    use strict; my @array = qw(A0-7:123:C B8-15:456:D); my $check = 'A4:123:C'; _check_range(\@array, $check) and print "in range\n"; sub _check_range { my $arr = shift; my $check = shift; my $regex = qr{^([a-zA-Z]+)(\d+)(?:-(\d+))?:(\d+):(\w+)}; $check =~ /$regex/ or return; my %check = ( 'char1', $1, 'digit1', $2, 'digit2', $4 , 'char2', $ +5 ); for( @$arr ){ if( /$regex/ ){ if( $check{char1} eq $1 and $check{char2} eq $5 ){ if( $check{digit2} == $4 ){ $check{digit1} >= $2 and $check{digit1} <= $3 and return 1 } } } } }

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://434275]
Approved by talexb
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others surveying the Monastery: (7)
As of 2017-11-18 11:07 GMT
Find Nodes?
    Voting Booth?
    In order to be able to say "I know Perl", you must have:

    Results (277 votes). Check out past polls.