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

With all of your suggestions on my intro Perl class assignment (see that OP here), I have come up with the following code...it is a blend of code, pseudocode, and otherwise - this is only a skeleton (and the regexes are purely off the top of my head, but they remind me what each has to do).

I decided to do the month conversions all in one hash, rather than do conversions in 2 or more steps (i.e. why 8, 08, and aug are all in one hash.) Since there weren't that many choices the table didn't get too large in this case.

So all I'm writing about is to see if I'm on the right track, get opinions, suggestions, constructive criticism, or whatever. (bearing in mind it's a skeleton)(also bearing in mind that at this stage I will tend to write things out more explicitly, rather than as tersely as they could be).

Thanks in advance!
#!usr/bin/perl #Script to parse dates such as the following: #Apr 8 1984, Apr 08 84, 4/8/84, 04/08/84, 08 Apr 1984 use warnings; use strict; #declare my vars and make sure they're empty my $MM = $DD = $YY = $YYYY = (); #take in date at command line and make text lowercase chomp (my $date = <>); $date = lc ($date); #parse Apr 8 1984 if ($date =~ /^\[a-zA-Z]{3}\s\d\s\d{4}$/){ split $date and assign each part to $MM $DD and $YYYY; output ($MM, $DD, $YYYY); #parse Apr 08 84 } elsif ($date =~ /^\[a-zA-Z]{3}\s\d{2}\s\d{2}$/) { split $date and assign each part to $MM $DD and $YY; convert $YY to 4 digits and assign to $YYYY; output ($MM, $DD, $YYYY); #parse 4/8/84 } elsif ($date =~ /^\d\/\d\/\d{2}$/) { split $date and assign each part to $MM $DD and $YY; convert $YY to 4 digits and assign to $YYYY; output ($MM, $DD, $YYYY); #parse 04/08/84 } elsif ($date =~ /^\d{2}\/\d{2}\/\d{2}$/) { split $date and assign each part to $MM $DD and $YY; convert $YY to 4 digits and assign to $YYYY; output ($MM, $DD, $YYYY); #parse 08 Apr 1984 } elsif ($date =~ /^\d{2}\s\[a-zA-Z]{3}\s\d{4}$/) { split $date and assign each part to $MM $DD and $YYYY; output ($MM, $DD, $YYYY); #contingency plan } else { print "your date is not of a recognizable format...good day.\n"; } sub output { #take in $MM $DD $YYYY with @_, parse $MM with %months #and print "fullmonth day, year" to STDOUT my %months = ( jan => January feb => February mar => March apr => April may => MAY jun => June jul => July aug => August sep => September oct => October nov => November dec => December 1 => January 2 => February 3 => March 4 => April 5 => MAY 6 => June 7 => July 8 => August 9 => September 10 => October 11 => November 12 => December 01 => January 02 => February 03 => March 04 => April 05 => MAY 06 => June 07 => July 08 => August 09 => September) print "$MM's{value} $DD's{value}, $YYYY's{value}\n"; }

Replies are listed 'Best First'.
Re: More Date Conversion Happiness, Part 2
by Zaxo (Archbishop) on Jan 11, 2004 at 05:00 UTC

    I like your hash approach to the months. I think you should take another look at the suggestions you got for using split.

    It would be good to use the possible ranges of values to identify the format, and to warn of ambiguous dates like 8/4/84. The locale pragmatic could help resolve issues like that.

    After Compline,
    Zaxo

Re: More Date Conversion Happiness, Part 2
by davido (Cardinal) on Jan 11, 2004 at 05:35 UTC
    The hash is a pretty good idea. Of course your current method of assigning the hash is 'pseudocode' because the months to the right of the fat comma (=>) aren't quoted. That could easily be solved by saying my %months = qw/01 January 02 March..../;

    There's another way to define the hash using a slice. I'm not sure if it's asthetically more or less pleasing than your version, but it's a few less keystrokes.

    my %months; @months{ '01'..'12', '1'..'12', qw/ jan feb mar apr may jun jul aug sep oct nov dec / } = ( qw/ January February March April May June July August September October November December /) x 3;

    Cheers!


    Dave

Re: More Date Conversion Happiness, Part 2
by neuroball (Pilgrim) on Jan 11, 2004 at 03:18 UTC

    There is not much more one can comment at until you come up with the first version of your script.

    The only thing I can come up with is a better style of writting your code.

    A coding style helps you to envision the code flow and also helps with tracking down simple one-off errors (I.e. a bracket to much, not enough brackets, ...).

    You might want to read this article about perl style guidelines.

    Example:

    /oliver/
      There is not much more one can comment at until you come up with the first version of your script.

      Of course...I guess what I'm asking is if I am headed totally the wrong way, going down a dead-end path, shoulda done X or Y...that kind of thing. Or, aside from modules, there's a better way to look at doing it

      A coding style helps you to envision the code flow and also helps with tracking down simple one-off errors (I.e. a bracket to much, not enough brackets, ...).

      Thanks for that - it's something I know I need to do, and this gives me some more good pointers on how to get there...thanks
Re: More Date Conversion Happiness, Part 2
by TomDLux (Vicar) on Jan 11, 2004 at 16:14 UTC

    Take another look at variable declaration. You $MM is local, but the otehrs are global. You want:

    my ( $MM, $DD, $YY, $YYYY );

    If you don't assign anything to them, they wind up undef, which is the same value you explicitly assign to them.


    The first two date formats differ only in zero-padding the day. Both will use the same split code, the only difference will be the precise return value. Similarly, the slash-delimited formats differ only in the segment of the hash used in looking up the corresponding month; otherwise they are identical.

    Now if you want a REAL challenge, figure out how to differentiate between US, English and European formats:

    • mm/dd/yy
    • dd/mm/yy
    • yy-mm-dd

    --
    TTTATCGGTCGTTATATAGATGTTTGCA

      All great stuff, thanks. I have another script which is just the portions of my pseudocode script that I have fleshed out and run and tested, and I discovered that local/global thing and fixed it.

      I see what you mean about that split code. I'm going to try to implement that as I flesh this thing out.
Re: More Date Conversion Happiness, Part 2
by CountZero (Bishop) on Jan 11, 2004 at 09:31 UTC
    Doesn't look bad (as far as pseudo-code goes, that is).

    Personally and depending on what your final result of the conversion has to be, I would have converted the month's name/number to a number and not to the full name of the month. Incidentally you have written the month of 'May' in all caps!

    It is probably easier to work with all data in numerical form, which is also the form expected/used by the built-in date functions.

    One more comment: if you are careful in crafting your regexes, you can do the splitting right there in the regex by using capturing parentheses and $1 $2 $3. Perhaps you should also allow the user to input extra/spurious whitespace (allow for \s+ instead of \s)

    CountZero

    "If you have four groups working on a compiler, you'll get a 4-pass compiler." - Conway's Law

      In this case the final result must be full month name...yea, I would have done the conversions differently had that not been the case.

      On the regexes, I've seen that done, but I'm new at this so I'm not gonna jump into that just yet (soon tho). Once I have this thing working in a way satisfactory to my instructor, I'll post it and ask everyone here how they'd do it and find out how I could have done it in 5 lines! :-D
Re: More Date Conversion Happiness, Part 2
by Not_a_Number (Prior) on Jan 11, 2004 at 19:37 UTC

    Just a small remark to add to the above. In consecutive lines (stripping out comments) you have the following:

    $date = lc ($date); if ($date =~ /^\[a-zA-Z]{3}\s\d\s\d{4}$/){

    Since you put the string $date into lower case in the first of these lines, you don't need to check for [A-Z]in the second...

    dave