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

Dear Monks,

Who won't my lexicals reset?

Thanks

#!/usr/bin/perl use strict; use warnings; while (<DATA>) { $_ =~ /(\d\d):(\d\d):(\d\d)/; my $hours = $1; my $minutes = $2; my $seconds = $3; print "$hours,$minutes,$seconds\n" } __DATA__ 01:23:45 06:54;32 23;45:16

Replies are listed 'Best First'.
Re: Regular expression and lexical variables
by davido (Cardinal) on Apr 17, 2011 at 08:23 UTC

    The regexp match operator returns true or false based on success or failure of the match. As you're seeing, it's not generally safe to assume things worked out and you got a match as you expected. When the match fails, $1, $2, and $3 aren't being re-set. It's not your lexicals, it's the fact that nothing new has been captured into $1, $2, and $3, so they retain their old value.

    Is this a trick question thrown at you by a teacher to see if you're looking closely enough at the data set? It seems a little fishy that semicolons would be scattered into time stamps at different locations in each stamp.


    Dave

Re: Regular expression and lexical variables
by wfsp (Abbot) on Apr 17, 2011 at 07:22 UTC
    You have ; as well as : in your data. Either fix your data or modify the regex.
    #!/usr/bin/perl use v5.12.2; use warnings; use strict; while (<DATA>) { $_ =~ /(\d\d)[:;](\d\d)[:;](\d\d)/; my $hours = $1; my $minutes = $2; my $seconds = $3; print "$hours,$minutes,$seconds\n" } __DATA__ 01:23:45 06:54;32 23;45:16
    update: You could introduce some error checking
    #!/usr/bin/perl use v5.12.2; use warnings; use strict; while (my $line = <DATA>) { if ($line =~ /(\d\d)[:;](\d\d)[:;](\d\d)/){ my $hours = $1; my $minutes = $2; my $seconds = $3; print "$hours,$minutes,$seconds\n"; } else{ print qq{bad line: $line\n}; } } __DATA__ 01:23:45 06:54;32 23;45:16 23_45_16
Re: Regular expression and lexical variables
by ikegami (Patriarch) on Apr 17, 2011 at 16:53 UTC
    Another way to check:
    while (<DATA>) { my ($hours, $minutes, $seconds) = /(\d\d):(\d\d):(\d\d)/ or next; print "$hours,$minutes,$seconds\n" }
Re: Regular expression and lexical variables
by anonymized user 468275 (Curate) on Apr 18, 2011 at 10:28 UTC
    Regexps should be tested and action taken when they fail, e.g.
    DATA: while (<DATA>) { chomp; $_ or next DATA; # allow empty lines /(\d\d):(\d\d):(\d\d)/ or die "corrupted data at line $.: $_\n"; # +but no other deviation my $hours = $1; etc.

    One world, one people