2012-07-06 6 views

Odpowiedz

15

Spróbuj tego:

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

upvote do użytku produkcyjnego nieuchwytnego, negatywnego zdania o zerowej szerokości. Chociaż (niestety) jak wskazuje Bill Ruppert, istnieje już moduł CPAN. –

+3

Chociaż * jest * rozwiązaniem CPAN, to też mi się podoba. Jest dobrze przemyślany, czytelny, pozbawiony zależności i tak dokładny jak rozwiązanie CPAN dla dowolnej liczby całkowitej. – DavidO

27

Korzystając Lingua::EN::Numbers::Ordinate. Z STRESZCZENIE:

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; 
    } 
    ... 
} 
7

Spróbuj krótkie podprogramu

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"; 
} 

wyjście

42nd 
521st 
113th 
+0

Jest coś, czego nie rozumiem tutaj w pełni. Dlaczego pętla 'for', gdy występuje tylko jeden element jako argument? Może również działać 'return int (shift). (qw/... '. Dla wielu parametrów pętla' for' nie działałaby ani z powodu instrukcji 'return', działa dobrze, ale czy tęskniłem za czymś na temat pętli? – Birei

+0

@Birei: po prostu sposób umieszczenia '$ _ [0]' na '$ _'. Twój sposób nie zadziałałby, ponieważ wyrażenie regularne potrzebuje wartości w' $ _' Jest to bardzo podobne do nowego 'danego' języka, ale ty nie można tego używać jako modyfikatora instrukcji, jak to możliwe z 'for' . – Borodin

+0

Ah, ok. Dziękuję.Nie otrzymałem punktu' $ _' .Należy go ** + 1 **. – Birei

2

Oto rozwiązanie which I originally wrote for a code golf challenge, nieznacznie przepisywane w celu dostosowania do zwykłych najlepszych praktyk dla kodu non-golfa :

$number =~ s/(1?\d)$/$1 . ((qw'th st nd rd')[$1] || 'th')/e; 

Sposób działania polega na tym, że wyrażenie regularne (1?\d)$ dopasowuje ostatnią cyfrę numeru plus poprzednią cyfrę, jeśli jest to 1. Substytucja używa następnie dopasowanych cyfr jako indeksu do listy (qw'th st nd rd'), odwzorowującej od 0 do th, od 1 do st, od 2 do nd, od 3 do rd i dowolnej innej wartości do undef. Wreszcie, operator || zastępuje undef z th.

Jeśli nie podoba Ci się s///e, w zasadzie można napisać to samo rozwiązanie np. tak:

for ($number) { 
    /(1?\d)$/ or next; 
    $_ .= (qw'th st nd rd')[$1] || 'th'; 
} 

lub jako funkcja:

sub ordinal ($) { 
    $_[0] =~ /(1?\d)$/ or return; 
    return $_[0] . ((qw'th st nd rd')[$1] || 'th'); 
} 
0

Innym rozwiązaniem (chociaż lubię istniejące wcześniej odpowiedzi, które są niezależne od zastosowania modułów lepiej):

use Date::Calc 'English_Ordinal'; 
print English_Ordinal $ARGV[0]; 
Powiązane problemy