On Sun, Feb 8, 2009 at 03:49, Gunnar Hjalmarsson <nore...@gunnar.cc> wrote:
> Chas. Owens wrote:
>>
>> On Sat, Feb 7, 2009 at 19:11, Gunnar Hjalmarsson <nore...@gunnar.cc>
>> wrote:
>>>
>>> TMTOWTDI
>>>
>>>   use Time::Local;
>>>   while (<DATA>) {
>>>       s{,(.+?),}{
>>>           my ($d, $m, $y) = split /\//, $1;
>>>           my $t = timelocal 0, 0, 0, $d, $m-1, $y;
>>>           ($d, $m, $y) = (localtime $t)[3..5];
>>>           sprintf ',%d-%02d-%02d,', $y+1900, $m+1, $d;
>>>       }e;
>>>   }
>>
>> snip
>>
>> And this would be the confusing, fragile mess I spoke of.
>
> Sorry, but I fail too see how using the s/// operator to extract the date
> field would be so much more confusing and fragile compared to split() +
> join().
snip

You are calling three functions (one of which is split) and assigning
returns three times inside the replacement.  Add on top of that the
fact that the regex only works for the second field.  Compare all of
that to calling two much simpler functions, a simple substitution, and
one assignment.  Try to imagine what happens six months from now when
you need to go back and perform a transformation on the fifth field.
Are you going to extend the regex to try to capture that value?  Or
are you just going to rewrite the code to use a split like you should
have in the first place?  Also, there may be a need to handle commas
in the fields at some point in the future.  This will entail using a
module like Text::CSV.  With the split code you can just replace the
split with the proper parsing function from the module.  With the
giant substitution code you pretty much have to rewrite the whole
thing.

I am all for using advanced features of Perl when it makes the code
clearer or more concise, but this code is longer than the split
version, involves more functions (including the confusing* localtime
and timelocal functions), and doesn't even do error checking on the
data.

On an unrelated topic, why are you using timelocal?  A much better
solution is to use the strftime function from the POSIX module:

#!/usr/bin/perl

use strict;
use warnings;

use POSIX;

while (<DATA>) {
        s{,([^,]+),}{
                my ($m, $d, $y) = $1 =~ m<^([0-9]+)/([0-9]+)/([0-9]+)$>
                        or die "$. has an invalid date format";
                strftime ",%Y%m%d,", 0, 0, 0, $d, $m - 1, $y - 1900;
        }e;
        print;
}

__DATA__
1,1/1/2009,optional,foo
2,1/2/2009,,bar
3,1/3/2009,,baz


Note how the split from your code has been changed to a regex.  This
is because split is indiscriminate.  This was good in my code because
it acted as future proofing against more fields being added to the
record** (which is unlikely to affect the meaning of earlier fields),
but bad here because we know the expected format of the date and the
chances of it not being that format and the code still being correct
at some point in the future is small.

* localtime pretty much only makes sense when you know the C based tm
structure it came from and timelocal, besides being a word play that
is too clever by half, is worse because it violates that structure***.
** also, if we wanted to throw an error because there were too few or
too many fields it would be easily achieved by asking the array how
many elements it held.
*** http://perldoc.perl.org/Time/Local.html#Year-Value-Interpretation

-- 
Chas. Owens
wonkden.net
The most important skill a programmer can have is the ability to read.

-- 
To unsubscribe, e-mail: beginners-unsubscr...@perl.org
For additional commands, e-mail: beginners-h...@perl.org
http://learn.perl.org/


Reply via email to