newbie Perl guy here. I have a Perl script (v5.26.1) that parses a logfile. For reasons beyond my control, the format of each date in the log is this:
"yyyy.mm.dd.hh.mm.ss"
e.g.:
"2022.09.19.16.35.00"
Note that year is always four digits, while month, day, hour, minute, and second are always two digits. (e.g. Sept is 09
)
I need to convert this string into a DateTime object for comparison purposes. I thought this exercise would be a breeze, but five hours and a lot of fruitless Google searches later, and I’m no-where close. Here’s my first attempt:
#!/usr/bin/perl
use warnings;
use strict;
sub transStrToDTime
{
# Example format of a date: "2022.09.19.16.35.00"
my $str = @_; # Only one input argument
use DateTime qw( );
my ($y,$m,$d,$h,$m,$s) = $str =~ /^([0-9]{4}).([0-9]{2}).([0-9]{2}).([0-9]{2}).([0-9]{2}).([0-9]{2})z/
or die;
my $dt = DateTime->new(
year => $y,
month => $m,
day => $d,
hour => $h,
minute => $m,
second => $s,
time_zone => 'local'
);
printf("=-=-=-=-=-=-=->>> "$dt"n");
}
my $str="2022.09.19.16.35.00";
transStrToDTime($str);
Code has a syntax error:
me@ubuntu:/home/me# ./toyPerl.pl
Died at ./toyPerl.pl line 16.
me@ubuntu:/home/me#
Where line 16 is:
my ($y,$m,$d,$h,$m,$s) = $str =~ /^([0-9]{4}).([0-9]{2}).([0-9]{2}).([0-9]{2}).([0-9]{2}).([0-9]{2})z/
Ugggggggghhhhhhhhh… After reading up on this topic and becoming more confused, I decided to do the conversion manually. I figured that all I had to do is:
split()
the string on.
- Build a new DateTime object with the string tokens as input:
Here’s that attempt:
#!/usr/bin/perl
use warnings;
use strict;
my $str="2022.09.19.16.35.00";
my @spl = split('.', $line);
#Lets look at the tokens before we build the DateTime object:
for(my $i = 0; $i <= $#spl; $i++){
print("$i) $spl[$i] n");
}
Output:
me@ubuntu:/home/me# ./toyPerl.pl
me@ubuntu:/home/me#
No output… meaning that split()
split "2022.09.19.16.35.00"
into zero tokens? Is $str
not a string, then? So what data type could it be?
#!/usr/bin/perl
use warnings;
use strict;
my $str="2022.09.19.16.35.00";
printf("Verifying that $str is a string:n");
printf("---> ${ref($str)}n");
Output:
me@ubuntu:/home/me# ./toyPerl.pl
Verifying that "2022.09.19.16.35.00" is a string:
Can't use string ("") as a SCALAR ref while "strict refs" in use at ./2222toyPerl.pl line 7.
me@ubuntu:/home/me#
Where line 7 is this line:
printf("---> ${ref($str)}n");
I’m so confused. The error message seems to say that my string isn’t a scalar. But I thought strings were scalar in Perl? ("A scalar is most often either a number or a string.") And why is the string reduced to an empty string (""
) in line 7?
Oh man. This post represents half a day’s work. Can anyone spot my syntax error in the first method? And why can’t I split()
string "2022.09.19.16.35.00"
? Is it not a string or something? Thank you.
2
Answers
When you put
It means you put the array in scalar context, and in scalar context, arrays return their size. What you want is to use list context:
Or better yet, use the idiomatic
shift
:You are also using two
$m
variables. Change one of them to something else. Revised code works as expected:Output:
The thing you call a syntax error in the first method is actually not a syntax error. Just your code that says
die
if the regex match fails. Note thatdie
without a message is not terribly informative. You might want to put something more useful there.In your second case, when you split on
'.'
, you are using a wildcard character.
, not a literal period. Hence the entire string is consumed and nothing is left. You might trysplit /./
instead.In the third case, I don’t know what you are doing here:
${ref($str)}
You are trying to dereference the return value fromref
? The return value fromref
is just a string, e.g.ARRAY
orSCALAR
. That’s not how you useref
. If you want to know what a variable contains, instead useData::Dumper
:Also, this line:
printf
when you can useprint
.printf
has a special usage.In addition to everything TLP said, you can use