Ответ 1
Попробуйте следующее:
my $ordinal;
if ($foo =~ /(?<!1)1$/) {
$ordinal = 'st';
} elsif ($foo =~ /(?<!1)2$/) {
$ordinal = 'nd';
} elsif ($foo =~ /(?<!1)3$/) {
$ordinal = 'rd';
} else {
$ordinal = 'th';
}
У меня есть число и нужно добавить суффикс: 'st', 'nd', 'rd', 'th'. Например, если число равно 42, то суффикс равен "nd", 521 - "st", а 113 - "th" и т.д. Мне нужно сделать это в perl. Любые указатели.
Попробуйте следующее:
my $ordinal;
if ($foo =~ /(?<!1)1$/) {
$ordinal = 'st';
} elsif ($foo =~ /(?<!1)2$/) {
$ordinal = 'nd';
} elsif ($foo =~ /(?<!1)3$/) {
$ordinal = 'rd';
} else {
$ordinal = 'th';
}
Используйте Lingua::EN::Numbers::Ordinate. Из краткого обзора:
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;
}
...
}
Попробуйте эту краткую подпрограмму
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";
}
Выход
42nd
521st
113th
Вот решение которое я изначально написал для пробного кода для кодов, слегка переписанное, чтобы соответствовать обычным лучшим практикам для кода, отличного от гольфа:
$number =~ s/(1?\d)$/$1 . ((qw'th st nd rd')[$1] || 'th')/e;
Как он работает, регулярное выражение (1?\d)$
соответствует последней цифре числа плюс предыдущая цифра, если она 1
. Затем подстановка использует совпадающую цифру в качестве индекса в список (qw'th st nd rd')
, сопоставление от 0 до th
, от 1 до st
, от 2 до nd
, от 3 до rd
и любое другое значение undef, Наконец, оператор ||
заменяет undef на th
.
Если вам не нравится s///e
, по существу одно и то же решение может быть написано, например. например:
for ($number) {
/(1?\d)$/ or next;
$_ .= (qw'th st nd rd')[$1] || 'th';
}
или как функция:
sub ordinal ($) {
$_[0] =~ /(1?\d)$/ or return;
return $_[0] . ((qw'th st nd rd')[$1] || 'th');
}
Другое решение (хотя мне нравятся предыдущие ответы, которые не зависят от использования модулей лучше):
use Date::Calc 'English_Ordinal';
print English_Ordinal $ARGV[0];