Как получить порядковый суффикс целого числа в Perl (например, st, nd, rd, th)

У меня есть номер, и мне нужно добавить суффикс: «st», «nd», «rd», «th». Так, например: если число равно 42, суффикс будет «nd», 521 — «st», 113 — «th» и так далее. Мне нужно сделать это в Perl. Любые указатели.


person bozo user    schedule 06.07.2012    source источник


Ответы (5)


Попробуй это:

my $ordinal;
if ($foo =~ /(?<!1)1$/) {
    $ordinal = 'st';
} elsif ($foo =~ /(?<!1)2$/) {
    $ordinal = 'nd';
} elsif ($foo =~ /(?<!1)3$/) {
    $ordinal = 'rd';
} else {
    $ordinal = 'th';
}
person Daniel Li    schedule 06.07.2012
comment
Проголосуйте за продуктивное использование неуловимого отрицательного обратного утверждения нулевой ширины. Хотя (к сожалению), как указывает Билл Руперт, для этого уже есть модуль CPAN. - person Andy Ross; 07.07.2012
comment
Несмотря на то, что существует решение CPAN, мне нравится и это. Он хорошо продуман, легко читаем, лишен зависимостей и так же точен, как решение CPAN для любого целого числа. - person DavidO; 07.07.2012
comment
То же самое, но переписано еще более пошло: 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"; }. (Примечание: это также возвращает сам номер) - person matemaciek; 26.09.2018

Используйте 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;
  }
  ...
}
person Bill Ruppert    schedule 06.07.2012

Попробуйте эту короткую подпрограмму

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
person Borodin    schedule 06.07.2012
comment
Я тут что-то не до конца понимаю. Зачем цикл for, когда в качестве аргумента используется только один элемент? Это также может сработать return int( shift ) . (qw/.... Для некоторых параметров цикл for не будет работать ни из-за оператора return. Он отлично работает как есть, но я что-то пропустил в цикле? - person Birei; 23.07.2012
comment
@Birei: это просто способ поместить $_[0] в $_. Ваш способ не сработает, так как регулярное выражение требует, чтобы значение было в $_. Это очень похоже на новое слово языка given, но вы не можете использовать его в качестве модификатора оператора, как вы можете использовать с for. - person Borodin; 23.07.2012
comment
Ах хорошо. Спасибо. Не понял смысла $_. Он заслуживает +1. - person Birei; 23.07.2012
comment
@BillRuppert: Спасибо, Билл. Я забыл, что писал это! Я думаю, что for это все, что должен делать сломанный given, но это уже другая история. - person Borodin; 05.06.2014

Вот решение, которое я изначально написал для игры в гольф, немного переписанное, чтобы соответствовать обычным рекомендациям для кода, не относящегося к гольфу. :

$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');
}
person Ilmari Karonen    schedule 25.07.2012

Другое решение (хотя мне больше нравятся уже существующие ответы, которые не зависят от использования модулей):

use Date::Calc 'English_Ordinal';
print English_Ordinal $ARGV[0];
person msh210    schedule 16.10.2015