No such thing as a small change PerlMonks

adding st,nd,rd and th to numbers

by anniyan (Monk)
 on Jul 19, 2005 at 12:58 UTC Need Help??
anniyan has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monks,

We would have come across the problem when we want to print like 1st, 2nd, 3rd, 4th....11th, 12th,.. ie. st, nd th should be given for the numbers accordingly.

I tried following code.

\$nouser = 5; if (\$nouser !~ /^\d{2}\$/) { \$nouser = \$nouser.'st' if (\$nouser =~ /(1)\$/); \$nouser = \$nouser.'nd' if (\$nouser =~ /(2)\$/); \$nouser = \$nouser.'rd' if (\$nouser =~ /(3)\$/); \$nouser = \$nouser.'th' if (\$nouser =~ /(4|5|6|7|8|9|0)\$/); } else { \$nouser = \$nouser.'th'; }

But when we come to 111th, 112th it wont work properly. Is there any module for this?

Regards,
Anniyan

Replies are listed 'Best First'.
Re: adding st,nd,rd and th to numbers
by gellyfish (Monsignor) on Jul 19, 2005 at 13:10 UTC

Ah! I thought I remembered that there is a module that would do this, but I couldn't remember what it was.

-Bryan

Re: adding st,nd,rd and th to numbers
by davorg (Chancellor) on Jul 19, 2005 at 13:11 UTC
Re: adding st,nd,rd and th to numbers
by mrborisguy (Hermit) on Jul 19, 2005 at 13:06 UTC

Note that your problem doesn't start at 111th and 112th. Your problem starts at 11th and 12th. 121st still follows your pattern, so really the only deviance you have from your pattern is when the last two numbers are 11, 12, or 13. See if you can add that special logic and you should be alright.

my \$nouser = 5; my \$suffix; \$suffix = 'st' if (\$nouser =~ /(1)\$/); \$suffix = 'nd' if (\$nouser =~ /(2)\$/); \$suffix = 'rd' if (\$nouser =~ /(3)\$/); \$suffix = 'th' if (\$nouser =~ /(4|5|6|7|8|9|0)\$/); \$suffix = 'th' if (\$nouser =~ /(11|12|13)\$/); \$nouser = \$nouser . \$suffix;

-Bryan

You're doing captures for nothing. Fix:

my \$suffix; \$suffix = 'st' if (\$nouser =~ /1\$/); \$suffix = 'nd' if (\$nouser =~ /2\$/); \$suffix = 'rd' if (\$nouser =~ /3\$/); \$suffix = 'th' if (\$nouser =~ /(?:4|5|6|7|8|9|0)\$/); \$suffix = 'th' if (\$nouser =~ /(?:11|12|13)\$/);

You're executing every regexp for nothing. Fix:

my \$suffix; if (\$nouser =~ /(?<!1)1\$/) { \$suffix = 'st'; } elsif (\$nouser =~ /(?<!1)2\$/) { \$suffix = 'nd'; } elsif (\$nouser =~ /(?<!1)3\$/) { \$suffix = 'rd'; } else { \$suffix = 'th'; }

Alternative styles:

While the existing Lingua module is probably the best solution, I thought I'd add to your list of styles a subroutine that I've used in the past:
sub ordinate (\$) { my \$num = shift; \$num =~ s/(\d*(11|12|13|4|5|6|7|8|9|0))\$/\$1th/ or \$num =~ s/(\d*(1))\$/\$1st/ or \$num =~ s/(\d*(2))\$/\$1nd/ or \$num =~ s/(\d*(3))\$/\$1rd/; return \$num; }

So, just out of curiosity, I benchmarked the alternatives above and my code. I don't test your first chunk of code, I start with the first example using the if/elsif/else structure. Results:

Rate Ordinate Method 3 Method 4 Method 2 Method 1 Ordinate 125/s -- -48% -50% -54% -64% Method 3 242/s 93% -- -4% -11% -30% Method 4 252/s 102% 5% -- -7% -27% Method 2 272/s 117% 13% 8% -- -21% Method 1 344/s 175% 42% 36% 27% --

It looks like your first pass at if/elsif/else is the best by quite a bit, and my approach is extremely slow. ;-) The code I used for benchmarking:

Larry Wall is Yoda: there is no try{} (ok, except in Perl6; way to ruin a joke, Larry! ;P)
The Code that can be seen is not the true Code
Re: adding st,nd,rd and th to numbers
by siracusa (Friar) on Jul 19, 2005 at 13:56 UTC

Here's the code that I used when I needed to do this:

if(\$mday =~ /(?<!1)1\$/) { \$date_word = \$mday . 'st' } elsif(\$mday =~ /(?<!1)2\$/) { \$date_word = \$mday . 'nd' } elsif(\$mday =~ /(?<!1)3\$/) { \$date_word = \$mday . 'rd' } else { \$date_word = \$mday . 'th' }

Using a module (as mentioned above) is probably a better idea, however...

Re: adding st,nd,rd and th to numbers
by mayhem (Hermit) on Jul 19, 2005 at 18:41 UTC
Re: adding st,nd,rd and th to numbers
by Your Mother (Bishop) on Jul 19, 2005 at 22:59 UTC

One more flavor.

sub ordinal { return "\$_[0]nd" if \$_[0] =~ /(?<!1)2\$/; return "\$_[0]rd" if \$_[0] =~ /(?<!1)3\$/; return "\$_[0]st" if \$_[0] =~ /(?<!1)1\$/; return "\$_[0]th"; }
Re: adding st,nd,rd and th to numbers
by zshzn (Hermit) on Jul 19, 2005 at 19:18 UTC
Is there any reason why you couldn't just use this?
my \$num = \$ARGV[0]; \$num .= 'st' if (substr(\$num, -1) == 1); \$num .= 'nd' if (substr(\$num, -1) == 2); \$num .= 'rd' if (substr(\$num, -1) == 3); \$num .= 'th' if (substr(\$num, -1) > 3); print "\$num\n";
Well, the 11st and 12nd reasons for one.

Update: the 10 reason is also malfunctioning.

-nuffin
zz zZ Z Z #!perl
Sorry, those few odd numbers obviously passed over my mind. I retract my answer.
If I can slightly add to that, it needs a similar case for 0.

It doesn't structure as if, elsif, else, because should it work on any case the addition will guarantee that it will not pass on any of the following.

Create A New User
Node Status?
node history
Node Type: perlquestion [id://476068]
Approved by RolandGunslinger
Front-paged by RolandGunslinger
help
Chatterbox?
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others chanting in the Monastery: (9)
As of 2018-06-19 13:20 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
Should cpanminus be part of the standard Perl release?

Results (114 votes). Check out past polls.

Notices?