Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

Replacing $mon with Jan, Feb, Mar by regex or other means

by jonnyfolk (Vicar)
on Apr 25, 2003 at 09:52 UTC ( #253115=perlquestion: print w/ replies, xml ) Need Help??
jonnyfolk has asked for the wisdom of the Perl Monks concerning the following question:

I thought I'd revisit a question I asked on the CB a couple of days ago, where my problem was solved (thanks Coruscate, tye, Mr. Muskrat et al), but a thought remained...

My question concerned replacing $mon in localtime with three letter equivalents. I was using the simpleton's

if ($mon == '00') { $mon = "Jan"; } elsif ...etc.
and of course I was quickly shown that there were shorter (at least in typing) means of achieving it.

I thought it would be interesting if fellow monks could come up with ways of achieving this and giving as clear an explanation of what is going on inside their solution, so that the thread would become a sort of compendium on how to solve this type of problem.

Or that's what I'm hoping, anyway...:)

Comment on Replacing $mon with Jan, Feb, Mar by regex or other means
Download Code
Re: Replacing $mon with Jan, Feb, Mar by regex or other means
by Bilbo (Pilgrim) on Apr 25, 2003 at 09:57 UTC

    Why not just put them in an array:

    my @months = qw(Jan Feb Mar Apr ...)

    Then just use $months[$mon].

Re: Replacing $mon with Jan, Feb, Mar by regex or other means
by Abigail-II (Bishop) on Apr 25, 2003 at 09:58 UTC
    use POSIX 'strftime'; print strftime "%m" => localtime;

    Or you could keep it simple and do

    print +(qw /Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec/)[$mon +]

    Abigail

Re: Replacing $mon with Jan, Feb, Mar by regex or other means
by Tanalis (Curate) on Apr 25, 2003 at 10:04 UTC
    There are two possible ways I'd do this ..

    $mon is always going to be a numeric index, between 0 and 11. We can set up an array of months, then use this index to select out each month in turn:

    my @months = ( qw/Jan Feb Mar Apr May ... Dec/ ); my $month = $months[$mon];
    Alternatively, and definitely overkill, would be to use the Date::Calc module: this contains a Month_to_Text function that can be used to do the same job:
    my $month = substr(Month_to_Text($mon + 1), 0, 3);
    On reflection, that's most definitely not as clear, or concise, and I much prefer the first solution.

    Just a couple of ideas.
    -- Foxcub
    A friend is someone who can see straight through you, yet still enjoy the view. (Anon)

Re: Replacing $mon with Jan, Feb, Mar by regex or other means
by BrowserUk (Pope) on Apr 25, 2003 at 10:14 UTC

    Put the 3-char abbrevs into a string and use substr to pick out the right one.

    perl -e"for my $mon (0..11) { print substr('JanFebMarAprMayJunJulAugSe +pOctNovDec', $mon*3, 3), $/; }" Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec

    Switch the quotes under unix.


    Examine what is said, not who speaks.
    1) When a distinguished but elderly scientist states that something is possible, he is almost certainly right. When he states that something is impossible, he is very probably wrong.
    2) The only way of discovering the limits of the possible is to venture a little way past them into the impossible
    3) Any sufficiently advanced technology is indistinguishable from magic.
    Arthur C. Clarke.
      I know you probably weren't serious.

      But it turns out that your approach isn't as slow as I thought it would be. It's still slower than using an array, but not terribly.

      Benchmark: running inlineArrayLookup, preBuiltArrayLookup, strftimeLoo +kup, substrLookup, each for at least 2 CPU seconds... inlineArrayLookup: 2 wallclock secs ( 2.12 usr + -0.01 sys = 2.11 CP +U) @ 543540.28/s (n=1146870) preBuiltArrayLookup: 1 wallclock secs ( 2.04 usr + -0.01 sys = 2.03 +CPU) @ 588310.34/s (n=1194270) strftimeLookup: 3 wallclock secs ( 1.76 usr + 0.37 sys = 2.13 CPU) +@ 216666.20/s (n=461499) substrLookup: 2 wallclock secs ( 2.09 usr + 0.00 sys = 2.09 CPU) @ +465374.16/s (n=972632) Rate strftimeLookup substrLookup inlineArrayLo +okup preBuiltArrayLookup strftimeLookup 216666/s -- -53% +-60% -63% substrLookup 465374/s 115% -- +-14% -21% inlineArrayLookup 543540/s 151% 17% + -- -8% preBuiltArrayLookup 588310/s 172% 26% + 8% --
      Comparing the strftime version isn't totally fair, since it's not a simple "month->string" converter, but requires a localtime list. But as others have pointed out, it will do locales correctly.


      --
      Mike

      Edit: Added strftime variant which I had overlooked.

      Edit by tye, change PRE to CODE around long lines

        To make a better comparison, you should strftimeLookup do a getMonthNumber as well. Now it's the only case that isn't penalized by an extra subroutine call. Or you could eliminate the call from all cases, the lookup time won't be different depending on the number of the month. Just use a fixed month number (but don't hardcode it as a literal, or else the compiler might pre-calculate some calculations).

        Abigail

        I do use this, though I usually put the constant information into a constant.

        use constant MONTHS=> 'JanFebMarAprMayJunJulAugSepOctNovDec';

        You'll find that this has little if any effect on the performance.


        Examine what is said, not who speaks.
        1) When a distinguished but elderly scientist states that something is possible, he is almost certainly right. When he states that something is impossible, he is very probably wrong.
        2) The only way of discovering the limits of the possible is to venture a little way past them into the impossible
        3) Any sufficiently advanced technology is indistinguishable from magic.
        Arthur C. Clarke.
Re: Replacing $mon with Jan, Feb, Mar by regex or other means
by zakb (Pilgrim) on Apr 25, 2003 at 11:12 UTC

    It may be worth considering that all of the above will be potentially incorrect for anything other than English, with the possible exception of the POSIX solution.

    Abigail-II, would the POSIX version use the correct translation for the current locale (e.g. Fev for Fevrier = February in french)?

      It should, but whether it does might depend on how strftime is implemented on your platform. Perl just calls the system library with the same name to do the work.

      Abigail

Re: Replacing $mon with Jan, Feb, Mar by regex or other means
by gawatkins (Monsignor) on Apr 25, 2003 at 11:49 UTC

    jonnyfolk,

    The best way that I have found to do this was using a hash.

    my %month3letter = ( 12 => 'Jan', 1 => 'Feb', 2 => 'Mar', 3 => 'Apr', 4 => 'May', 5 => 'Jun', 6 => 'Jul', 7 => 'Aug', 8 => 'Sep', 9 => 'Oct', 10 => 'Nov', 11 => 'Dec' );

    Or-well mabye I just like hashes, anyway I have had a great deal of success with it.

    Thanks,

    Greg

Re: Replacing $mon with Jan, Feb, Mar by regex or other means
by Mr. Muskrat (Abbot) on Apr 25, 2003 at 14:10 UTC

    Here's what I said in the CB:
    my $mon = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec)[(localtime)[4]];

    Create an anonymous array a list containing the abbreviated month names and return the array list element indexed by the zero based month number returned by (localtime)[4].

    Updated: chromatic caught my blunder.

Re: Replacing $mon with Jan, Feb, Mar by regex or other means
by jonnyfolk (Vicar) on Apr 25, 2003 at 20:09 UTC
    Well, in the CB Coruscate came up with the regex:
    ($mon) = localtime =~ /\A.{3} (.{3})/
    Does anybody else think this is a good idea?

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://253115]
Approved by broquaint
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others romping around the Monastery: (6)
As of 2014-09-21 19:54 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    How do you remember the number of days in each month?











    Results (175 votes), past polls