Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

Problem when comparing strings as opposed to numerical values

by dkhalfe (Acolyte)
on Jul 19, 2012 at 19:03 UTC ( [id://982690]=perlquestion: print w/replies, xml ) Need Help??

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

Hello all. For reference:

column relationship value filter_or_append order a <= 0.3 filter 1 b == abc append 2 c <= 0.3 filter 3

My program reads in this filter file and stores each value in an array.

if (eval "$hash{$filter[0]->[0]} $filter[0]->[1] $filter[0]->[ +2]") { if (eval $hash{$filter[1]->[0]} $filter[1]->[1] $filter[1] +->[2]) { if (eval "$hash{$filter[2]->[0]} $filter[2]->[1] $filt +er[2]->[2]") { print OUTFILE $line, "\n"; } } }

Whats going on: If the hash of column a evaluates to less than or equal to the value specified in the filter file (.03), continue. This part works. Then, if the hash of column b evaluates to 'equal' (== or eq; I have tried both meaning I have changed the values for column b in the filter file to both '==' and 'eq' and tried to run the program that way but no luck) the value specified in the filter file (abc), continue. This part does not work - Any comparison/evaluations of numerical values works and I can print the results to an output file. However, when I try to do this same comparison/evaluation with strings, wrong output (if any) is printed to the output file. What is a solution to compare/evaluate a string with the code I have already written?

Thank you!

Replies are listed 'Best First'.
Re: Problem when comparing strings as opposed to numerical values
by BrowserUk (Patriarch) on Jul 19, 2012 at 20:26 UTC

    That is easily dealt with using the dispatch table method. Here are a few examples:

    C:\test>dynop Enter criteria: 0 > xray zpepocpu 325 82.7545166015625 zgvappww 187 85.540771484375 zoedyjzb 780 75.0732421875 zapvcywd 987 71.014404296875 yasxnblr 328 93.7652587890625 zsqavfzn 777 28.8421630859375 yfxbhnqz 560 69.0948486328125 Enter criteria: 2 > 99.0 ahfijvsa 492 99.3072509765625 kpfaqzzz 419 99.8504638671875 Enter criteria: 0 =~ mid phmidnpi 931 60.980224609375 Enter criteria: 1 >= 900 zapvcywd 987 71.014404296875 phmidnpi 931 60.980224609375 fcaabsvp 907 62.908935546875 qqnmneah 987 27.685546875 foyqaqgx 901 51.214599609375 Enter criteria: 0 lt b ahfijvsa 492 99.3072509765625 abnualfk 166 57.2265625 axarlwit 430 82.5531005859375

    And the test code:

    #! perl -slw use strict; use Regexp::Common; $|++; my @cmpOps = qw[ < lt <= le == eq >= ge > gt != ne ]; my %ops; for my $op ( @cmpOps, qw[ =~ !~ ] ) { $ops{ $op } = eval "sub{ \$_[0] $op \$_[1] }"; } my %cmpX = @cmpOps; my $DATApos = tell( DATA ); while( 1 ) { printf "\nEnter criteria: "; my( $field, $op, $const ) = split ' ', scalar <STDIN>; warn "Bad field no" and next unless $field >= 0 and $field <=2; warn "Bad op" and next unless exists $ops{ $op }; warn "Bad constant" and next unless defined $const; $op = $cmpX{ $op } if $const !~ m[^$RE{num}{real}$] and exists $cmpX{ $op }; local $\; seek DATA, $DATApos, 0; while( <DATA> ) { my @f = split ' '; print if $ops{ $op }->( $f[ $field ], $const ); } } __DATA__ sinbpoax 462 15.7684326171875 szaarvxz 611 56.6070556640625 pavpcufm 738 46.96044921875 pidfkhrt 208 84.4329833984375 wcudntgc 257 84.68017578125 ezohziff 731 63.9801025390625 fjprkxqe 742 3.0517578125 zpepocpu 325 82.7545166015625 ptogapva 865 98.92578125 rbbruxkd 292 69.2962646484375 ctkejtxq 253 2.57568359375 ixllpbfr 539 71.1822509765625 eufrsfdm 197 76.8829345703125 zgvappww 187 85.540771484375 lcsenyrn 98 95.6298828125 ehroxvni 616 57.757568359375 gwxrsmqt 186 41.4886474609375 igvgajxj 728 13.9495849609375 jlwqafze 533 14.4073486328125 hlfordlo 722 42.8619384765625 gzsvvjtd 894 90.93017578125 fupuumgb 141 92.8192138671875 okeecgnh 413 25.146484375 ahfijvsa 492 99.3072509765625 dbbvbkem 725 31.854248046875 ppfljtcl 202 8.8653564453125 ugszniuc 471 42.5811767578125 wlmjvzuh 216 14.898681640625 zoedyjzb 780 75.0732421875 zapvcywd 987 71.014404296875 xmludpni 730 6.9000244140625 ezxkcxxv 163 97.528076171875 yasxnblr 328 93.7652587890625 ogoryjnp 750 46.759033203125 mckiqrfr 40 23.193359375 cerfqydo 15 42.7459716796875 dcnsueah 401 44.1741943359375 phmidnpi 931 60.980224609375 doyhkmsv 734 63.41552734375 fmwfplux 436 63.836669921875 ujrexkvq 518 48.8189697265625 cgrmavrb 282 57.26318359375 lfjxkyxf 419 30.82275390625 xlyrewup 767 84.4024658203125 jkdqaiog 536 42.193603515625 irdyxuvd 122 21.7437744140625 kogolxtn 879 86.944580078125 lcloacfc 837 93.438720703125 degylchc 616 78.96728515625 mbflgtft 713 69.4183349609375 svhihmfm 116 41.021728515625 fcaabsvp 907 62.908935546875 kcsrcluu 327 4.693603515625 tjqruhsz 769 92.9931640625 lobwyxip 509 1.96533203125 iefkdodr 737 27.83203125 gteyukkt 865 89.007568359375 fcontiyx 82 74.1851806640625 mpajgdol 95 92.816162109375 zsqavfzn 777 28.8421630859375 dipyswtm 403 21.337890625 xpogpvcz 275 57.58056640625 qqnmneah 987 27.685546875 klfloyxx 481 17.2943115234375 yfxbhnqz 560 69.0948486328125 fpcxgycp 683 86.9354248046875 foyqaqgx 901 51.214599609375 lelltkzq 751 22.8179931640625 tfumslgj 2 98.388671875 fxwwzfvm 355 4.022216796875 ghdfdppk 820 40.5303955078125 pwarwsir 505 83.404541015625 abnualfk 166 57.2265625 bzilevkn 185 9.94873046875 rkwcbiac 780 69.696044921875 clgtdkmc 363 37.9913330078125 vubvfxbo 102 21.2158203125 tbhugaup 163 88.9984130859375 nedcbeax 780 36.6607666015625 dexeryuf 470 81.5216064453125 fvbfbknp 451 1.763916015625 wtwntrem 759 94.93408203125 ikhtsurg 814 52.72216796875 axarlwit 430 82.5531005859375 ojftvscz 539 16.7877197265625 kpfaqzzz 419 99.8504638671875 stkadgrt 34 94.464111328125 vmxmtijm 380 63.299560546875 jsofkrzq 603 23.91357421875 tvsjhhmd 203 5.4962158203125 bungnlqk 35 18.22509765625 ugewjtpn 175 42.2393798828125 udbwvomt 136 16.17431640625 whzukvul 532 17.0928955078125 huqhtllj 264 37.04833984375 dxamgnyd 710 39.17236328125 pgdleajt 362 80.2276611328125 pjhxddem 69 79.669189453125 squnbfvs 557 60.11962890625 uznmzvug 357 42.8192138671875

    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

    The start of some sanity?

Re: Problem when comparing strings as opposed to numerical values
by ig (Vicar) on Jul 19, 2012 at 20:50 UTC

    I wonder if you are missing quotes in your second if.

    I'm guessing that you also need to put quotes around your strings in what I'm guessing you want to be a string eval (the second if). The string you want to evaluate should probably be something like "'string' eq 'string'".

    It might help you to examine what you are evaluating. You might use the debugger but I would probably use print or warn myself. Something like:

    if (eval "$hash{$filter[0]->[0]} $filter[0]->[1] $filter[0]->[ +2]") { print "eval \"$hash{$filter[1]->[0]} $filter[1]->[1] $filt +er[1]->[2]\""; if (eval "$hash{$filter[1]->[0]} $filter[1]->[1] $filter[1 +]->[2]") { if (eval "$hash{$filter[2]->[0]} $filter[2]->[1] $filt +er[2]->[2]") { print OUTFILE $line, "\n"; } } }

    When you see what you are evaluating, the problem will likely become evident.

    FWIW: I don't think I would use eval as you are trying to. I would probably do something more like the follwing:

    sub match { my ($hash, $filter) = @_; if($filter->[1] eq '<=') { return( $hash{$filter->[0]} <= $filter->[2] ); } elsif($filter->[1] eq 'eq') { return( $hash{$filter->[0]} eq $filter->[2] ); } else { die "unsupported comparator: $filter->[$index]->[1]"; } } if( match($hash, $filters->[0]) and match($hash, $filters->[1]) and match($hash, $filters->[2]) ) { print OUTFILE $line, "\n"; }

    If I was going to use eval, I would definitely check for errors after each eval. I suspect if you did so, you would find that the eval in your second if gives a compile error - but it's only a guess. If you did add error handling to your implementation with eval, I would find it even harder to read than what you have currently, which is already too hard for my taste, but that's just me. In any case, if you want to know why your program isn't doing what you expect, a very good place to start is error handling and reporting. To this end, you might find strict and warnings helpful.

      adding in the single quotes seemed to have fixed the problem. I appreciate the advice and am going to try and implement the 'sub match' code you have provided. Thank you!

Re: Problem when comparing strings as opposed to numerical values
by aitap (Curate) on Jul 19, 2012 at 20:16 UTC

    Firstly, there is no need in nested if's:

    if ((eval "$hash{$filter[0]->[0]} $filter[0]->[1] $filter[0]->[2]") && + (eval $hash{$filter[1]->[0]} $filter[1]->[1] $filter[1]->[2]) && (eval "$hash{$filter[2]->[0]} $filter[2]->[1] $filter[2]->[2]")) { print OUTFILE $line, "\n"; }

    Secondly, you have quotes (") missing in the second statement. This can be the source of the problem. You can try using other quoting operators.

    Thirdly, it can be safer to write a specific function to perform any needed checks on your data:

    sub check { my ($a, $check, $b) = @_; if ($check eq "==") { return $a == $b; } elsif ($check eq ">=") { return $a >= $b; } elsif ($check eq "<=") { return $a <= $b; } elsif ($check eq "eq") { return $a eq $b; } else { die "Unimplemented check $check" } } if (&check($hash{$filter[0]->[0]},$filter[0]->[1],$filter[0]->[2]) && +&check(...) && &check(...)) { print OUTFILE $line; }
    Some syntax problems caused by special characters inside the strings will be also avoided by this method.

    Sorry if my advice was wrong.

      I tried it with the quotes but theres no output to the file.

      I also tried:

       (eval /$hash{/$filter[1]->[0]} $filter[1]->[1] $filter[1]->[2])

      that didnt work either. It only works when I manually type in 'eq' - Example:

       (eval $hash{$filter[1]->[0]} eq $filter[1]->[2])

      But my whole point is to use the reference to the array to pull the variable out which should be 'eq' in this case. I am stumped. Any ideas on what to do?

        What if you print what you are trying to eval? I mean, run perl -d <your script>.pl, set a breakpoint on the line where the string comparsion occurs (b <line number>), run program to that line (c) and enter: x "$hash{$filter[1]->[0]} $filter[1]->[1] $filter[1]->[2]". What will it print?

        Maybe using eval "q{$hash{$filter[1]->[0]}} $filter[1]->[1] q{$filter[1]->[2]}" can help, but it will break too if the strings contain some "{" or "}". What if you check for $@ special variable after running your evals?

        Are you sure it won't be easier and safer to write a special sub to perform the checking?

        Sorry if my advice was wrong.
Re: Problem when comparing strings as opposed to numerical values
by Anonymous Monk on Jul 19, 2012 at 19:15 UTC

    What are you trying to accomplish with those evals?

    Have you considered what will happen if your input contains a string value along the lines of "};  system('format c:'); #"

      Yes. Later on, I am going to add regexes to check the values.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others goofing around in the Monastery: (4)
As of 2024-03-19 11:03 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found