简体   繁体   中英

Perl: Comparing numbers within a string

Given the following input:

A| 11 162 60 90 -- 141 184

B| 231 322 -- 306 305 285 350

For A, I want to check if 141 lies between (11,162) OR (60,90) inclusive. If yes, print "In A, 141 lies between (11,162)".

Then, I want to check if 184 lies between (11,162) OR (60,90) inclusive. Since it doesn't, nothing needs to be printed.

Similarly, for B, I need to print the numbers that lie between (231, 322).

I wrote the following Perl code but I am not getting the correct output.

#!/usr/bin/perl -w
open LIST, "input.txt";
while($line=<LIST>)
{
@elem=split (/\|/,$line);
@nextone=split("--",$elem[1]);
@nextoneone = split(" ",$nextone[0]);
@nexttwo=split(" ",$nextone[1]);

if ($nexttwo[0] > $nextoneone[0] && $nexttwo[0] < $nextoneone[1])
{
print"$elem[0]\t $nexttwo[0]\t $nextoneone[0]\t $nextoneone[1]\n";
}
elsif ($nexttwo[0] > $nextoneone[2] && $nexttwo[0] < $nextoneone[3])
{
print"$elem[0]\t $nexttwo[0]\t $nextoneone[2]\t $nextoneone[3]\n";
}
elsif ($nexttwo[1] > $nextoneone[0] && $nexttwo[1] < $nextoneone[1])
{
print"$elem[0]\t $nexttwo[1]\t $nextoneone[0] \t$nextoneone[1]\n";
}
elsif ($nexttwo[1] > $nextoneone[2] && $nexttwo[1] < $nextoneone[3])
{
print"$elem[0]\t $nexttwo[1]\t $nextoneone[2] \t$nextoneone[3]\n";
}
}
   close (LIST);
   exit;

I don't know how many elements are there in each row. Therefore, I do not know how to implement a loop for comparison. Any guidance on how to improve the code will be appreciated.

Thank you for your help.

Firstly, I would change a couple of things about your script. 1) use strict - it'll mean you catch any typos

2) give variables more meaningful names - I've changed some that make sense based on what I saw, but I don't know what your script does, so you may have better ones

3) Output some debug, while you're developing it, so you can see what it's doing and why it's not working

You will need two loops - one to loop over the values in the part of the string to the left of '--' and one to loop over the conditions on the right side. You want to loop through the values in the outer loop and then each time through that you should loop through ALL the conditions in the inner loop.

    use strict;
    #!/usr/bin/perl -w
    open LIST, "input.txt";
    my $line;
    while($line=<LIST>) {
        my ($label, $content) =split (/\|/,$line);
        my ($conditionstring, $valuestring) =split("--",$content);
        my (@conditions) = split(" ",$conditionstring);
        my (@values) =split(" ",$valuestring);
        foreach my $this_val (@values) {
                my $matched_one_condition = 0;
                for (my  $f=0; $f< scalar(@conditions);$f+=2) {


                        print "Comparing $this_val to $conditions[$f] and to            $conditions[$f+1]\n";

                        if (($this_val > $conditions[$f]) && ($this_val < $conditions[$f+1])) {
                                $matched_one_condition= 1;

                        }
                }
                if ($matched_one_condition) {
                        print "$this_val\n";

                }
        }
}

Note - I've left the debug line in there

Use a loop over the values if you do not know their number:

#!/usr/bin/perl
use warnings;
use strict;
use feature 'say';

while (<DATA>) {
    my ($header, $rangeS, $pointS) = /(.*)\|(.*) -- (.*)/;
    my @ranges = $rangeS =~ /([^ ]+ [^ ]+)/g;
    my @points = split / /, $pointS;

    for my $point (@points) {
        for my $range (@ranges) {
            my ($from, $to) = split / /, $range;
            if ($from <= $point and $point <= $to) {
                say "In $header, $point lies between ($from,$to)";
                last;   # Comment this line to get all the ranges for each point.
            }
        }
    }
}

__DATA__
A| 11 162 60 90 -- 141 184
B| 231 322 -- 306 305 285 350
C| 10 20 30 40 -- 1 2 3 4 5 6 7 8 9
D| 10 20 10 40 -- 1 10 20 40 10

i took a whack at your problem. hopefully you find some value in it. i did take the liberty of sorting the ranges to take care of the case of line B eg 306, 305.

#!/bin/env perl
use strict;
use warnings;

while ( <DATA> ) {
    my @line = /\w+|\d+/g;
    my( $h, $ranges, $tests ) = (
        $line[0], [ [ sort @line[1,2] ], [ sort @line[3,4] ] ], [ @line[5,6] ]
    );
    map {
        my $test = $_;
        map {
            print "In $h, $test lies between (", join( ', ', @$_ ), ")\n"
                if grep { /^$test$/ } ( $_->[0] .. $_->[1] )
        } ( @$ranges )
    } @$tests
}

__DATA__
A| 11 162 60 90 -- 141 184
B| 231 322 -- 306 305 285 350

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM