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...:)
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 | [reply] [d/l] [select] |
Re: Replacing $mon with Jan, Feb, Mar by regex or other means
by Bilbo (Pilgrim) on Apr 25, 2003 at 09:57 UTC
|
my @months = qw(Jan Feb Mar Apr ...)
Then just use $months[$mon]. | [reply] [d/l] [select] |
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)?
| [reply] |
|
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
| [reply] [d/l] |
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)
| [reply] [d/l] [select] |
Re: Replacing $mon with Jan, Feb, Mar by regex or other means
by BrowserUk (Patriarch) on Apr 25, 2003 at 10:14 UTC
|
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.
| [reply] [d/l] |
|
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 | [reply] [d/l] [select] |
|
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
| [reply] [d/l] [select] |
|
|
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.
| [reply] [d/l] |
Re: Replacing $mon with Jan, Feb, Mar by regex or other means
by gawatkins (Monsignor) on Apr 25, 2003 at 11:49 UTC
|
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
| [reply] [d/l] |
Re: Replacing $mon with Jan, Feb, Mar by regex or other means
by Mr. Muskrat (Canon) 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.
| [reply] [d/l] [select] |
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? | [reply] [d/l] |
|
|