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

Hello monks

I new to perl and I can't really tell why this code is not working :

#!/usr/bin/perl -w use strict; use locale; use warnings; #use diagnostics; use utf8; binmode(STDIN, "encoding(utf8)"); binmode(STDOUT, "encoding(utf8)"); binmode(STDERR, "encoding(utf8)"); my $data_file = "data.txt"; my ($start, $end); open (DATA, '<:utf8', $data_file) || die "Couldn't open $data_file : $ +!\n"; print "Start time (format : yyyy.mm.dd.hh):\n"; chomp (my $start_input = <STDIN>); print "End time (format : yyyy.mm.dd.hh):\n"; chomp (my $end_input = <STDIN>); if ($start_input =~ /\d\d\d\d/ && $end_input =~ /\d\d\d\d/){ while (<DATA>){ if (/$start_input\d\d\d\d\d\d/ .. /$end_input\d\d\d\d\d\d/){ if ($_ =~ /(.*)\t(.*)\t(.*)/){ print "Date = $1" . "\t" . "Temp_moy_DegCs = $2" . "\ +t" . "HR_moy_s = $3\n"; } } } } if ($start_input =~ /\d\d\d\d\.\d\d/ && $end_input =~ /\d\d\d\d\.\d\d/ +){ $start_input =~ tr/\.//d; print "$start_input\n"; $end_input =~ tr/\.//d; print "$end_input\n"; while (<DATA>){ if (/$start_input\d\d\d\d/ .. /$end_input\d\d\d\d/){ if ($_ =~ /(.*)\t(.*)\t(.*)/){ print "Date = $1" . "\t" . "Temp_moy_DegCs = $2" . "\ +t" . "HR_moy_s = $3\n"; } } } } close (DATA);

When I comment one of the first "if" loops it works just fine for one of the date formats ('yyyy' or 'yyyy.mm'). I also tried using the "elsif", but it's the same thing. Also it still doesn't work by executing all the "if" statments in the same "while" loop.

The source file looks like this

1998032602 -6 77 1998032603 -7 82 1998032604 -7,8 81 1998032605 -8,3 82 1998032606 -8,6 85 1998032607 -2,5 62 1998032608 2,1 37 1998032609 5,5 25 1998032610 8,9 16 1998032611 11 16 1998032612 12,9 15 1998032613 13,3 13 1998032614 13,4 14 1998032615 13,1 16 1999093022 7,2 96 1999093023 5,6 98 1999100100 5,7 99 1999100101 5,9 99 1999100102 5,4 99 1999100103 5,9 99 1999100104 5,9 99 1999100105 5,5 99 1999100106 4,2 99 1999100107 6 99 1999100108 9,3 82 1999100109 12,1 64 1999100110 14,5 50 1999100111 16,5 47 1999100112 17,8 49 1999100113 18,5 49 1999100114 18,6 48

Thank you

Replies are listed 'Best First'.
Re: Consecutive if loops
by tobyink (Canon) on Mar 18, 2013 at 16:56 UTC

    I think the logic you want is:

    if ($start_input =~ /\d\d\d\d\.\d\d/ && $end_input =~ /\d\d\d\d\.\d\d/ +) { ...; } elsif ($start_input =~ /\d\d\d\d/ && $end_input =~ /\d\d\d\d/) { ...; }

    This is because you've got two conditionals which overlap. Test specific conditions before generic ones. Compare:

    use v5.12; my $name = "Toby"; { say "FIRST BLOCK"; if ($name =~ /^T/) { say "name starts with T" } elsif ($name =~ /^Toby/) { say "name is Toby" } say "END BLOCK"; } { say "SECOND BLOCK"; if ($name =~ /^Toby/) { say "name is Toby" } elsif ($name =~ /^T/) { say "name starts with T" } say "END BLOCK"; }

    The "name starts with T" test is more generic than the "name is Toby" test, so if you perform the "name starts with T" test first, it will effectively swallow up the other test.

    package Cow { use Moo; has name => (is => 'lazy', default => sub { 'Mooington' }) } say Cow->new->name
Re: Consecutive if loops
by davido (Cardinal) on Mar 18, 2013 at 17:12 UTC

    I added a few comments to your script. I don't exactly know what outcome you want, but I do spot a few things that are most likely errors.

    #!/usr/bin/perl -w use strict; use locale; use warnings; use diagnostics; use utf8; binmode(STDIN, ":encoding(utf8)"); # prepend the colon to "encoding" +. binmode(STDOUT, ":encoding(utf8)"); # prepend the colon to "encoding" +. binmode(STDERR, ":encoding(utf8)"); # prepend the colon to "encoding" +. my $data_file = "data.txt"; my ($start, $end); # Warning: this works, but DATA is special. Better to use a different + name. open (DATA, '<:utf8', $data_file) || die "Couldn't open $data_file : $ +!\n"; # Consider using IO::Prompt::Tiny, or IO::Prompt::Hooked. print "Start time (format : yyyy.mm.dd.hh):\n"; chomp (my $start_input = <STDIN>); print "End time (format : yyyy.mm.dd.hh):\n"; chomp (my $end_input = <STDIN>); # Questionable: Are you really intending to pass any input that contai +ns four # contiguous digits? Maybe so, but seems like an inadequate validatio +n. if ($start_input =~ /\d\d\d\d/ && $end_input =~ /\d\d\d\d/){ while (<DATA>){ # Even more questionable: None of your suggested input formats wou +ld match. # Did you mean $start_input =~ /\d{6}/ ? When would the input eve +r have # six contiguous digits? if (/$start_input\d\d\d\d\d\d/ .. /$end_input\d\d\d\d\d\d/){ if ($_ =~ /(.*)\t(.*)\t(.*)/){ print "Date = $1" . "\t" . "Temp_moy_DegCs = $2" . "\t" . "HR +_moy_s = $3\n"; } } } } if ($start_input =~ /\d\d\d\d\.\d\d/ && $end_input =~ /\d\d\d\d\.\d\d/ +){ # Maybe you intended to do this immediately after receiving input. +That would # fix the second "if", but would break the fourth "if" conditional. $start_input =~ tr/\.//d; print "$start_input\n"; $end_input =~ tr/\.//d; print "$end_input\n"; while (<DATA>){ # I don't see this ever working. Did you mean $start_input =~ /\d +{4}/ .. ? if (/$start_input\d\d\d\d/ .. /$end_input\d\d\d\d/){ if ($_ =~ /(.*)\t(.*)\t(.*)/){ print "Date = $1" . "\t" . "Temp_moy_DegCs = $2" . "\t" . "HR +_moy_s = $3\n"; } } } } close (DATA);

    Dave

Re: Consecutive if loops
by poj (Abbot) on Mar 18, 2013 at 16:51 UTC

    I'm guessing the problem is when you enter yyyy the code runs in both the yyyy and the yyyy.mm blocks. Either add start ^ and end $ anchors to the regex statements

    if ($start_input =~ /^\d\d\d\d$/ && $end_input =~ /^\d\d\d\d$/){

    or swap the order so the if yyyy.mm is first then elseif yyyy

    poj
Re: Consecutive if loops
by Jim (Curate) on Mar 18, 2013 at 16:35 UTC

    Describe what the script is supposed to do. It's not clear to me from briefly inspecting the code. I don't understand the intended logic.

      I actually got it by experimenting with the code. I wanted to give a user different levels of control. The goal was to display the content of the second and the third between two dates. And the user could choose to input, the year, the month, the day, the hour or all of them.

      I just had to add "^" and "$" in the first regex in order to mark the beginning and the end of the string :

      elsif ($start_input =~ /^\d\d\d\d\.\d\d\.\d\d\.\d\d$/ && $end_input =~ + /^\d\d\d\d\.\d\d\.\d\d\.\d\d$/){ $start_input =~ tr/\.//d; print "$start_input\n"; $end_input =~ tr/\.//d; print "$end_input\n"; while (<DATA>){ if (/$start_input/ .. /$end_input/){ if ($_ =~ /(.*)\t(.*)\t(.*)/){ print "Date = $1" . "\t" . "Temp_moy_DegCs = $2" . "\ +t" . "HR_moy_s = $3\n"; } } } }

      it seems to work now.

Re: Consecutive if loops
by hdb (Monsignor) on Mar 18, 2013 at 16:59 UTC
    I would translate the users inputs into a 10 digit number by padding it with zeroes removing any dots. You can then numerically compare to the first field in your datafile. Just be careful with the end date/time... Apologies for not providing sample code but I have to run.
    For every complex problem there is an answer that is clear, simple, and wrong. H. L. Mencken