Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

Match Numeric Range

by PilotinControl (Pilgrim)
on Aug 18, 2015 at 03:52 UTC ( #1138948=perlquestion: print w/replies, xml ) Need Help??

PilotinControl has asked for the wisdom of the Perl Monks concerning the following question:

Good Evening Monks!

I have a light sensor and I need to capture a numeric range from the serial monitor to which I've already done commands using simple letter matches. Number matches I am completely lost with outside of the normal $data == 5 (do something) and so on. I need to capture a range of 200-300 and 400-500 so I can issue a command based on any number within that range. For example:

if ($range ==/300-400/) { exit; } if ($range == /425-500/) { print STDOUT "LIGHTS ON"\n; }

and so on. Of course I know that it is not that simple. I do believe it has to do with regexp and numerical expressions? Thanks in advanced!

Replies are listed 'Best First'.
Re: Match Numeric Range
by Athanasius (Bishop) on Aug 18, 2015 at 04:06 UTC

      @OP

      You could also write the conditional as

      if ($range >= 300 and $range <= 400)

      In this case it actually does not make a difference which one you use, but

      open my $fh, '<', $filename || die;
      and
      open my $fh, '<', $filename or die;

      are two totally different things due to different order of precedence. (A verbose explanation can be found at 'or' vs '', '&&' vs 'and'.)

      Hello Athanasius!

      Thanks for the reply and the write up. There is no delimitor such as "-", ":", "," and so on it is white space..and the photo resistor sends the following to the serial monitor: Light - 235, 226, 212, 256, 280 every one second and this is an ever changing number and like wise if it is Dark - 345, 332, 389, 367 every one second when the photo resistor is covered. So that is why I need to capture a range of numbers for light and dark so the lights will either be turned on or turned off....and it is always 3 digits in length.

Re: Match Numeric Range
by dbuckhal (Hermit) on Aug 18, 2015 at 05:31 UTC
    Flip-flop, maybe?
    perl -le '@full = ( 0..100 ); for ( @full ) { print STDOUT "$_: LIGHTS ON" if /20/ .. /30/; print STDOUT "$_: LIGHTS OFF" if /60/ .. /70/; } ' __output__ 20: LIGHTS ON 21: LIGHTS ON 22: LIGHTS ON 23: LIGHTS ON 24: LIGHTS ON 25: LIGHTS ON 26: LIGHTS ON 27: LIGHTS ON 28: LIGHTS ON 29: LIGHTS ON 30: LIGHTS ON 60: LIGHTS OFF 61: LIGHTS OFF 62: LIGHTS OFF 63: LIGHTS OFF 64: LIGHTS OFF 65: LIGHTS OFF 66: LIGHTS OFF 67: LIGHTS OFF 68: LIGHTS OFF 69: LIGHTS OFF 70: LIGHTS OFF
    Though I do not know the proper syntax with variable assignment, so cannot turn the durn lights off! So, it half works....
    perl -le '@full = ( 0..20 ); for $ea ( @full ) { print STDOUT "$ea: LIGHTS ON" if $ea =~ /6/ .. /10/; print STDOUT "$ea: LIGHTS OFF" if $ea =~ /15/ .. /20/; } ' __output__ 6: LIGHTS ON 7: LIGHTS ON 8: LIGHTS ON 9: LIGHTS ON 10: LIGHTS ON 11: LIGHTS ON 12: LIGHTS ON 13: LIGHTS ON 14: LIGHTS ON 15: LIGHTS ON 15: LIGHTS OFF 16: LIGHTS ON 16: LIGHTS OFF 17: LIGHTS ON 17: LIGHTS OFF 18: LIGHTS ON 18: LIGHTS OFF 19: LIGHTS ON 19: LIGHTS OFF 20: LIGHTS ON 20: LIGHTS OFF
    Hope it helps!

      Hello dbuckhal...I added the correct syntax and in theory it does work...when applied to my situation it does not. Thanks for the input!

Re: Match Numeric Range
by roboticus (Chancellor) on Aug 18, 2015 at 12:43 UTC

    PilotinControl:

    If you're just wanting to simplify conditional statements like the ones you've shown, I typically use a function like this:

    use strict; use warnings; sub between { my ($min, $val, $max) = @_; return $val>=$min && $val<=$max; } for my $range (450, 475, 500, 550, 450, 350, 250, 100) { print "Range: $range\n"; if (between(300, $range, 400)) { exit; } if (between(425, $range, 500)) { print "LIGHTS ON\n"; } }
    $ perl t.pl Range: 450 LIGHTS ON Range: 475 LIGHTS ON Range: 500 LIGHTS ON Range: 550 Range: 450 LIGHTS ON Range: 350

    If you need to get fancier and build your functions dynamically (such as reading the values from a file), I tend to use a closure to generate them:

    #!/usr/bin/env perl use strict; use warnings; # Build the functions my @tests; while (<DATA>) { my ($min, $max, $message) = split /\s+/, $_, 3; push @tests, make_test_function($min, $max, $message); } my $range = 0; while ($range < 600) { print "Range: $range\n"; for my $test (@tests) { $test->($range); } $range += int(100*rand); } sub make_test_function { my ($min, $max, $message) = @_; return sub { my $val = shift; print $message if $val >= $min and $val <= $max; } } __DATA__ 100 350 In range A 200 500 In range B 300 400 In range C
    $ perl t.pl Range: 0 Range: 10 Range: 10 Range: 25 Range: 56 Range: 144 In range A Range: 208 In range A In range B Range: 254 In range A In range B Range: 323 In range A In range B In range C Range: 379 In range B In range C Range: 468 In range B Range: 530 Range: 550 Range: 557

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

      Thanks roboticus...the script is looking for the range of numbers dynamically in real time: 400-500 = Lights Off and 200-300 = Lights On. These numbers are generated via the photo resistor and is read from the serial port. The script is turned on and runs in the backround and once one of those numbers in the specified range has been detected the lights will either turn on or turn off. The while loop freezes my script as its looking for the range of numbers. The loops needs to continually be checking for that range of numbers as it will eventually trigger other things to happen.

        This kind of thing can be okay for progressive checking. I normal dislike this style of code/logic but it seems a good fit for this kind of problem.

        if ( $range > 500 ) { WAT_OP(); } elsif ( $range >= 425 ) { some_op(); } elsif ( $range > 400 ) { some_other_op(); } elsif ( $range > 300 ) { exit 0; } else { complete_tree_op(); }

        You can also do something more dispatchy–

        my @action_tree = ( { test => sub { $_[0] >= 300 && $_[0] <= 400 }, action => sub { print "GUDNITES\n"; CORE::exit(0 +) } }, { test => sub { $_[0] >= 425 && $_[0] <= 500 }, action => sub { print "OHAI\n" } } ); while ( my $signal = <SIGNAL_SOURCE> ) { $_->{test}->($signal) && $_->{action}->() for @action_tree; }

        I'm not advocating either, or that second style of terseness, or any style or approach for that matter. Just expanding the library of options. :P

Re: Match Numeric Range
by pme (Prior) on Aug 18, 2015 at 15:51 UTC
    Hi PilotinControl,

    You may apply hystersis. The state will be set to 1 if the value goes above three times the upper limit or it will be set to 0 if the value goes below lower limit three times.

      Hello PME!

      I will most certainly take a look at this as this code may have a good use on some other functions I am trying to achieve thanks!

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1138948]
Approved by Athanasius
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others meditating upon the Monastery: (5)
As of 2019-12-05 21:52 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Strict and warnings: which comes first?



    Results (151 votes). Check out past polls.

    Notices?