I have number and need to add the suffix: 'st', 'nd', 'rd', 'th'. So for example: if the number is 42 the suffix is 'nd' , 521 is 'st' and 113 is 'th' and so on. I need to do this in perl. Any pointers.
Try this:
my $ordinal;
if ($foo =~ /(?<!1)1$/) {
$ordinal = 'st';
} elsif ($foo =~ /(?<!1)2$/) {
$ordinal = 'nd';
} elsif ($foo =~ /(?<!1)3$/) {
$ordinal = 'rd';
} else {
$ordinal = 'th';
}
sub ordinal { my $n = shift; return "${n}st" if $n =~ /(?<!1)1$/; return "${n}nd" if $n =~ /(?<!1)2$/; return "${n}rd" if $n =~ /(?<!1)3$/; return "${n}th"; }
. (Note: this also returns the number itself) –
Exhibition Use Lingua::EN::Numbers::Ordinate. From the synopsis:
use Lingua::EN::Numbers::Ordinate;
print ordinate(4), "\n";
# prints 4th
print ordinate(-342), "\n";
# prints -342nd
# Example of actual use:
...
for(my $i = 0; $i < @records; $i++) {
unless(is_valid($record[$i]) {
warn "The ", ordinate($i), " record is invalid!\n";
next;
}
...
}
Try this:
my $ordinal;
if ($foo =~ /(?<!1)1$/) {
$ordinal = 'st';
} elsif ($foo =~ /(?<!1)2$/) {
$ordinal = 'nd';
} elsif ($foo =~ /(?<!1)3$/) {
$ordinal = 'rd';
} else {
$ordinal = 'th';
}
sub ordinal { my $n = shift; return "${n}st" if $n =~ /(?<!1)1$/; return "${n}nd" if $n =~ /(?<!1)2$/; return "${n}rd" if $n =~ /(?<!1)3$/; return "${n}th"; }
. (Note: this also returns the number itself) –
Exhibition Try this brief subroutine
use strict;
use warnings;
sub ordinal {
return $_.(qw/th st nd rd/)[/(?<!1)([123])$/ ? $1 : 0] for int shift;
}
for (42, 521, 113) {
print ordinal($_), "\n";
}
output
42nd
521st
113th
for
loop when there is only one element as argument? It could also work return int( shift ) . (qw/...
. For several parameters the for
loop wouldn't work neither because of the return
statement. It works fine as is, but did I miss something about the loop? –
Freckle $_[0]
into $_
. Your way wouldn't work as the regular expression needs the value to be in $_
. It's very like the new given
language word but you can't use that as a statement modifier as you can with for
. –
Hypsometry $_
. It deserves a +1. –
Freckle for
is all the broken given
should do, but that's another story –
Hypsometry Here's a solution which I originally wrote for a code golf challenge, slightly rewritten to conform to usual best practices for non-golf code:
$number =~ s/(1?\d)$/$1 . ((qw'th st nd rd')[$1] || 'th')/e;
The way it works is that the regexp (1?\d)$
matches the last digit of the number, plus the preceding digit if it is 1
. The substitution then uses the matched digit(s) as an index to the list (qw'th st nd rd')
, mapping 0 to th
, 1 to st
, 2 to nd
, 3 to rd
and any other value to undef. Finally, the ||
operator replaces undef with th
.
If you don't like s///e
, essentially the same solution could be written e.g. like this:
for ($number) {
/(1?\d)$/ or next;
$_ .= (qw'th st nd rd')[$1] || 'th';
}
or as a function:
sub ordinal ($) {
$_[0] =~ /(1?\d)$/ or return;
return $_[0] . ((qw'th st nd rd')[$1] || 'th');
}
Another solution (though I like the preexisting answers that are independent of using modules better):
use Date::Calc 'English_Ordinal';
print English_Ordinal $ARGV[0];
And here's an entirely non-tricky way to do it.
sub english_ordinal( $n ) {
my @suffixes = qw( th st nd rd th th th th th th );
my $x = $n % 100;
my $suffix;
if ( $x >= 10 && $x <= 19 ) {
$suffix = 'th';
}
else {
$suffix = $suffixes[$x % 10];
}
return "$n$suffix";
}
Could you make it take up much less space, be more clever, and maybe run faster? Sure, but the rest of the answers have that covered.
Might as well have some unit tests on it while we're at it.
my %tests = (
0 => '0th',
1 => '1st',
2 => '2nd',
3 => '3rd',
4 => '4th',
5 => '5th',
6 => '6th',
7 => '7th',
8 => '8th',
9 => '9th',
10 => '10th',
11 => '11th',
12 => '12th',
13 => '13th',
14 => '14th',
15 => '15th',
16 => '16th',
17 => '17th',
18 => '18th',
19 => '19th',
20 => '20th',
21 => '21st',
22 => '22nd',
23 => '23rd',
24 => '24th',
25 => '25th',
26 => '26th',
27 => '27th',
28 => '28th',
29 => '29th',
30 => '30th',
100 => '100th',
101 => '101st',
102 => '102nd',
111 => '111th',
);
while ( my ($n,$s) = each %tests ) {
is( english_ordinal($n), $s, "$n -> $s" );
}
© 2022 - 2024 — McMap. All rights reserved.