Tôi có số và cần thêm hậu tố: 'st', 'nd', 'rd', 'th'. Vì vậy, ví dụ: nếu số là 42 hậu tố là 'nd', 521 là 'st' và 113 là 'th' và cứ thế. Tôi cần làm điều này trong perl. Bất kỳ con trỏ nào.Làm cách nào để lấy hậu tố thứ tự của số nguyên trong Perl (như st, nd, rd, th)
Trả lời
Hãy thử điều này:
my $ordinal;
if ($foo =~ /(?<!1)1$/) {
$ordinal = 'st';
} elsif ($foo =~ /(?<!1)2$/) {
$ordinal = 'nd';
} elsif ($foo =~ /(?<!1)3$/) {
$ordinal = 'rd';
} else {
$ordinal = 'th';
}
Sử dụng Lingua::EN::Numbers::Ordinate. Từ tóm tắt:
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;
}
...
}
Hãy thử chương trình con ngắn gọn này
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";
}
đầu ra
42nd
521st
113th
Có điều gì đó tôi không hiểu đầy đủ ở đây. Tại sao một vòng lặp 'for' khi chỉ có một phần tử làm đối số? Nó cũng có thể làm việc 'return int (shift). (qw/... '. Đối với một số tham số, vòng lặp' for' sẽ không hoạt động vì câu lệnh 'return'. Nó hoạt động tốt như vậy, nhưng tôi có bỏ sót điều gì đó về vòng lặp không? – Birei
@Birei: nó chỉ là một cách để đặt '$ _ [0]' vào '$ _'. Cách của bạn sẽ không hoạt động vì biểu thức chính quy cần giá trị nằm trong' $ _'. Nó giống như từ ngữ 'given' mới nhưng bạn không thể sử dụng điều đó làm công cụ sửa đổi câu lệnh như bạn có thể với 'for'. – Borodin
Ah, ok. Cảm ơn bạn. Không nhận được điểm' $ _'. Nó xứng đáng là ** ** 1 **. – Birei
Dưới đây là một giải pháp which I originally wrote for a code golf challenge, hơi viết lại cho phù hợp với thông lệ tốt nhất thông thường cho mã phi golf :
$number =~ s/(1?\d)$/$1 . ((qw'th st nd rd')[$1] || 'th')/e;
Cách hoạt động của nó là regexp (1?\d)$
khớp với chữ số cuối cùng của số, cộng với số trước nếu nó là 1
. Thay thế sau đó sử dụng (các) chữ số phù hợp làm chỉ mục cho danh sách (qw'th st nd rd')
, ánh xạ 0 đến th
, 1 đến st
, 2 đến nd
, 3 đến rd
và bất kỳ giá trị nào khác để hoàn tác. Cuối cùng, toán tử ||
thay thế undef bằng th
.
Nếu bạn không thích s///e
, về cơ bản, giải pháp tương tự có thể được viết, ví dụ: như thế này:
for ($number) {
/(1?\d)$/ or next;
$_ .= (qw'th st nd rd')[$1] || 'th';
}
hoặc như là một chức năng:
sub ordinal ($) {
$_[0] =~ /(1?\d)$/ or return;
return $_[0] . ((qw'th st nd rd')[$1] || 'th');
}
Một giải pháp khác (mặc dù tôi thích câu trả lời từ trước đó là độc lập của việc sử dụng các module tốt hơn):
use Date::Calc 'English_Ordinal';
print English_Ordinal $ARGV[0];
Upvote để sử dụng hiệu quả của sự khẳng định ngược chiều rộng tiêu cực khó nắm bắt. Mặc dù (đáng buồn) như Bill Ruppert chỉ ra, có một mô-đun CPAN cho điều này rồi. –
Mặc dù có * là * một giải pháp CPAN, tôi cũng thích cái này. Nó cũng được suy nghĩ, dễ đọc, không phụ thuộc và chính xác như giải pháp CPAN cho bất kỳ số nguyên nào. – DavidO