Hiển thị số với hậu tố thứ tự trong PHP


148

Tôi muốn hiển thị số như sau

  • 1 là 1,
  • 2 là 2,
  • ...,
  • 150 như 150.

Làm thế nào tôi nên tìm đúng hậu tố thứ tự (st, nd, nd hoặc th) cho mỗi số trong mã của tôi?


2
Xem câu trả lời của tôi ở đây. stackoverflow.com/questions/69262/ Câu hỏi đó là dành cho .NET, nhưng tôi đã trả lời bằng một giải pháp PHP, vì vậy nó sẽ giúp bạn giải quyết.
nickf

Cách duy nhất tôi có thể nghĩ để làm điều này là có một câu lệnh if tăng lên cho mọi số bạn có thể có, IE, nếu (1) sau đó "st" otherif (2) rồi "nd", v.v. nếu (23000) thì " thứ hai ". Đó là một vấn đề nếu bạn có số lớn nhưng bạn có thể viết chương trình viết mã cho bạn, nó có thể lặp tất cả các số in ifs để bạn sao chép + dán vào mã của bạn.
Tom Gullen

2
@Tom, một bảng tra cứu có thể tốt hơn, chỉ cần khởi tạo nó với 23000 giá trị và nhận giá trị tại chỉ số n, trong đó n là số bạn muốn thứ tự.
John Boker

2
Đại tá mảnh đạn. bạn có thể xuất sắc nhưng không phải tất cả. bằng mọi cách cảm ơn vì đã thể hiện sự quan tâm đến câu hỏi của tôi
ArK

@ John, ý tưởng rất rất thông minh, sẽ rất nhanh để truy cập cũng như mỗi chỉ số đại diện cho số bạn đang tìm kiếm.
Tom Gullen

Câu trả lời:


282

từ wikipedia :

$ends = array('th','st','nd','rd','th','th','th','th','th','th');
if (($number %100) >= 11 && ($number%100) <= 13)
   $abbreviation = $number. 'th';
else
   $abbreviation = $number. $ends[$number % 10];

Trong trường hợp $numberlà số bạn muốn viết. Hoạt động với bất kỳ số tự nhiên.

Là một chức năng:

function ordinal($number) {
    $ends = array('th','st','nd','rd','th','th','th','th','th','th');
    if ((($number % 100) >= 11) && (($number%100) <= 13))
        return $number. 'th';
    else
        return $number. $ends[$number % 10];
}
//Example Usage
echo ordinal(100);

Mặc dù ban đầu hơi khó hiểu, nhưng bây giờ tôi nghĩ nó thể hiện tốt nhất cách hệ thống hậu tố thứ tự làm việc cho tiếng Anh.
erisco

5
Tôi thích giải pháp của bạn. Ngoài ra, nếu bạn không muốn tạo số 0, hãy sửa đổi dòng cuối cùng thành$abbreviation = ($number)? $number. $ends[$number % 10] : $number;
Gavin Jackson

1
@GavinJackson sự bổ sung của bạn vào giải pháp tuyệt vời này thực sự đã giúp tôi vượt qua (+1). Bạn có thể vui lòng giải thích cho tôi những gì đang xảy ra trong tính toán? Tôi muốn hiểu. Chúc mừng! EDIT: Tìm thấy câu trả lời: nhà điều hành có điều kiện
Andrew Fox

Xin lỗi, đã phải phá vỡ 111 phiếu bầu thành 112: D Biến nó thành một chức năng trong Delphi cùng với một ứng dụng demo: pastebin.com/wvmz1CHY
Jerry Dodge

1
@HafezDivandari - bạn có chắc không? Mới thử nghiệm với 7.1.19 và dường như hoạt động tốt
Iacopo

141

PHP có chức năng tích hợp sẵn cho việc này . Nó thậm chí còn xử lý quốc tế hóa!

$locale = 'en_US';
$nf = new NumberFormatter($locale, NumberFormatter::ORDINAL);
echo $nf->format($number);

Lưu ý rằng chức năng này chỉ có sẵn trong PHP 5.3.0 trở lên.


15
Lưu ý điều này cũng yêu cầu PECL intl> = 1.0.0
rymo

4
Bạn có biết nếu có thể có được số thứ tự ở dạng từ? ví dụ đầu tiên, thứ hai, thứ ba vv thay vì 1st, 2nd, 3rd ...
its_me

@jeremy Khi tôi cố gắng sử dụng NumberFormatter, nó luôn đưa ra một lỗi đó NumberFomatter file not found. Làm thế nào bạn làm việc xung quanh này?
jhnferraris

1
@Jhn bạn phải cài đặt tiện ích mở rộngapt-get install php5-intl
Aley

@Aley tôi thấy. Yii có một bộ định dạng tích hợp mà chúng tôi đang sử dụng ngay bây giờ. heh
jhnferraris

20

Điều này có thể được thực hiện trong một dòng bằng cách tận dụng chức năng tương tự trong các hàm ngày / giờ tích hợp của PHP. Tôi khiêm tốn nộp:

Giải pháp:

function ordinalSuffix( $n )
{
  return date('S',mktime(1,1,1,1,( (($n>=10)+($n>=20)+($n==0))*10 + $n%10) ));
}

Giải thích chi tiết:

Hàm tích hợp date()có logic hậu tố để xử lý các phép tính ngày thứ n của tháng. Hậu tố được trả về khi Sđược đưa ra trong chuỗi định dạng:

date( 'S' , ? );

Kể từ khi date()đòi hỏi một dấu thời gian (đối với ?trên), chúng tôi sẽ vượt qua số nguyên của chúng tôi $ndaytham số để mktime()và sử dụng hình nộm giá trị của 1cho hour, minute, second, và month:

date( 'S' , mktime( 1 , 1 , 1 , 1 , $n ) );

Điều này thực sự thất bại một cách duyên dáng trên các giá trị ngoài phạm vi cho một ngày trong tháng (nghĩa là $n > 31) nhưng chúng ta có thể thêm một số logic nội tuyến đơn giản vào giới hạn $nở 29:

date( 'S', mktime( 1, 1, 1, 1, ( (($n>=10)+($n>=20))*10 + $n%10) ));

Giá trị dương duy nhất( Tháng 5 năm 2017 ) điều này không thành công $n == 0, nhưng điều đó dễ dàng được khắc phục bằng cách thêm 10 trong trường hợp đặc biệt đó:

date( 'S', mktime( 1, 1, 1, 1, ( (($n>=10)+($n>=20)+($n==0))*10 + $n%10) ));

Cập nhật, tháng 5 năm 2017

Theo quan sát của @donatJ, các lỗi trên 100 (ví dụ "111st"), vì các >=20kiểm tra luôn luôn trả về đúng. Để thiết lập lại những thế kỷ này, chúng tôi thêm một bộ lọc để so sánh:

date( 'S', mktime( 1, 1, 1, 1, ( (($n>=10)+($n%100>=20)+($n==0))*10 + $n%10) ));

Chỉ cần bọc nó trong một chức năng cho thuận tiện và tắt bạn đi!


14

Đây là một lót:

$a = <yournumber>;
echo $a.substr(date('jS', mktime(0,0,0,1,($a%10==0?9:($a%100>20?$a%10:$a%100)),2000)),-2);

Có lẽ là giải pháp ngắn nhất. Tất nhiên có thể được bọc bởi một chức năng:

function ordinal($a) {
  // return English ordinal number
  return $a.substr(date('jS', mktime(0,0,0,1,($a%10==0?9:($a%100>20?$a%10:$a%100)),2000)),-2);
}

Trân trọng, Paul

EDIT1: Sửa mã cho 11 đến 13.

EDIT2: Sửa mã cho 111, 211, ...

EDIT3: Bây giờ nó hoạt động chính xác cũng cho bội số của 10.


Tôi thích cách tiếp cận này, nhưng than ôi, nó không hoạt động :-( Ngày 30 xuất hiện vào ngày 30, 40 đến 40, v.v.
Flukey

1
Ừ, xin lỗi. Khi tôi đọc câu hỏi tôi đã nghĩ, hey, điều này nên có thể bằng một dòng mã. Và tôi chỉ cần gõ nó đi. Như bạn thấy trong các chỉnh sửa của mình, tôi đang tiến bộ. Sau lần chỉnh sửa thứ ba bây giờ tôi nghĩ nó đã hoàn thành. Ít nhất là tất cả các số từ 1 đến 150 in ra độc đáo trên màn hình của tôi.
Paul

Có vẻ tốt lên tới 500! (chưa thử nó nhiều hơn thế). Làm tốt lắm! :-)
Flukey

13

từ http://www.phpro.org/examples/Ordinal-Suffix.html

<?php

/**
 *
 * @return number with ordinal suffix
 *
 * @param int $number
 *
 * @param int $ss Turn super script on/off
 *
 * @return string
 *
 */
function ordinalSuffix($number, $ss=0)
{

    /*** check for 11, 12, 13 ***/
    if ($number % 100 > 10 && $number %100 < 14)
    {
        $os = 'th';
    }
    /*** check if number is zero ***/
    elseif($number == 0)
    {
        $os = '';
    }
    else
    {
        /*** get the last digit ***/
        $last = substr($number, -1, 1);

        switch($last)
        {
            case "1":
            $os = 'st';
            break;

            case "2":
            $os = 'nd';
            break;

            case "3":
            $os = 'rd';
            break;

            default:
            $os = 'th';
        }
    }

    /*** add super script ***/
    $os = $ss==0 ? $os : '<sup>'.$os.'</sup>';

    /*** return ***/
    return $number.$os;
}
?> 

9

Câu trả lời đơn giản và dễ dàng sẽ là:

$Day = 3; 
echo date("S", mktime(0, 0, 0, 0, $Day, 0));

//OUTPUT - rd

Không nói gì về ngày tháng trong câu hỏi tho. Dù sao tôi cũng đã nâng cấp - đó là một giải pháp nhanh chóng và đơn giản khi bạn biết phạm vi số sẽ là <32
cronoklee

8

Tôi đã viết cái này cho PHP4. Nó hoạt động tốt và nó khá kinh tế.

function getOrdinalSuffix($number) {
    $number = abs($number) % 100;
    $lastChar = substr($number, -1, 1);
    switch ($lastChar) {
        case '1' : return ($number == '11') ? 'th' : 'st';
        case '2' : return ($number == '12') ? 'th' : 'nd';
        case '3' : return ($number == '13') ? 'th' : 'rd'; 
    }
    return 'th';  
}

Vishal Kumar, bạn có thể mở rộng / giải thích / giải thích thêm một chút không? Tks!
iletras

4

bạn chỉ cần áp dụng chức năng nhất định.

function addOrdinalNumberSuffix($num) {
  if (!in_array(($num % 100),array(11,12,13))){
    switch ($num % 10) {
      // Handle 1st, 2nd, 3rd
      case 1:  return $num.'st';
      case 2:  return $num.'nd';
      case 3:  return $num.'rd';
    }
  }
  return $num.'th';
}

3

Nói chung, bạn có thể sử dụng điều đó và gọi echo get_places_opes (100);

<?php
function get_placing_string($placing){
    $i=intval($placing%10);
    $place=substr($placing,-2); //For 11,12,13 places

    if($i==1 && $place!='11'){
        return $placing.'st';
    }
    else if($i==2 && $place!='12'){
        return $placing.'nd';
    }

    else if($i==3 && $place!='13'){
        return $placing.'rd';
    }
    return $placing.'th';
}
?>

2

Tôi đã tạo ra một hàm không dựa vào date();hàm của PHP vì nó không cần thiết, nhưng cũng làm cho nó nhỏ gọn và ngắn như tôi nghĩ hiện có thể.

: (tổng cộng 121 byte)

function ordinal($i) { // PHP 5.2 and later
  return($i.(($j=abs($i)%100)>10&&$j<14?'th':(($j%=10)>0&&$j<4?['st', 'nd', 'rd'][$j-1]:'th')));
}

Mã nhỏ gọn hơn dưới đây.

Nó hoạt động như sau :

printf("The %s hour.\n",    ordinal(0));   // The 0th hour.
printf("The %s ossicle.\n", ordinal(1));   // The 1st ossicle.
printf("The %s cat.\n",     ordinal(12));  // The 12th cat.
printf("The %s item.\n",    ordinal(-23)); // The -23rd item.

Những điều cần biết về chức năng này :

  • Nó liên quan đến các số nguyên âm giống như các số nguyên dương và giữ dấu.
  • Nó trả về 11, 12, 13, 811, 812, 813, v.v. cho mười số như mong đợi.
  • Nó không kiểm tra số thập phân, nhưng sẽ để lại cho họ tại chỗ (sử dụng floor($i), round($i)hoặc ceil($i)ở phần đầu của câu lệnh return cuối cùng).
  • Bạn cũng có thể thêm format_number($i)vào đầu câu lệnh hoàn trả cuối cùng để lấy số nguyên được phân tách bằng dấu phẩy (nếu bạn đang hiển thị hàng nghìn, hàng triệu, v.v.).
  • Bạn chỉ có thể xóa $itừ đầu câu lệnh return nếu bạn chỉ muốn trả về hậu tố thứ tự mà không cần nhập gì.

Hàm này hoạt động bắt đầu PHP 5.2 được phát hành vào tháng 11 năm 2006 hoàn toàn do cú pháp mảng ngắn. Nếu bạn có phiên bản trước đó, thì vui lòng nâng cấp vì bạn đã gần một thập kỷ lỗi thời! Không, chỉ cần thay thế nội tuyến ['st', 'nd', 'rd']bằng một biến tạm thời có chứa array('st', 'nd', 'rd');.

Hàm tương tự (không trả về đầu vào), nhưng chế độ xem bùng nổ của hàm ngắn của tôi để hiểu rõ hơn:

function ordinal($i) {
  $j = abs($i); // make negatives into positives
  $j = $j%100; // modulo 100; deal only with ones and tens; 0 through 99

  if($j>10 && $j<14) // if $j is over 10, but below 14 (so we deal with 11 to 13)
    return('th'); // always return 'th' for 11th, 13th, 62912th, etc.

  $j = $j%10; // modulo 10; deal only with ones; 0 through 9

  if($j==1) // 1st, 21st, 31st, 971st
    return('st');

  if($j==2) // 2nd, 22nd, 32nd, 582nd
    return('nd'); // 

  if($j==3) // 3rd, 23rd, 33rd, 253rd
    return('rd');

  return('th'); // everything else will suffixed with 'th' including 0th
}

Cập nhật mã :

Đây là phiên bản sửa đổi ngắn hơn 14 byte (tổng 107 byte):

function ordinal($i) {
  return $i.(($j=abs($i)%100)>10&&$j<14?'th':@['th','st','nd','rd'][$j%10]?:'th');
}

Hoặc càng ngắn càng tốt, ngắn hơn 25 byte (tổng cộng 96 byte):

function o($i){return $i.(($j=abs($i)%100)>10&&$j<14?'th':@['th','st','nd','rd'][$j%10]?:'th');}

Với chức năng cuối cùng này, chỉ cần gọi o(121);và nó sẽ thực hiện chính xác như các chức năng khác mà tôi đã liệt kê.

Cập nhật mã số 2 :

Ben và tôi đã làm việc cùng nhau và cắt giảm 38 byte (tổng cộng 83 byte):

function o($i){return$i.@(($j=abs($i)%100)>10&&$j<14?th:[th,st,nd,rd][$j%10]?:th);}

Chúng tôi không nghĩ rằng nó có thể có thể ngắn hơn thế này! Sẵn sàng để được chứng minh là sai, tuy nhiên. :)

Hy vọng tất cả các bạn thích.


bạn không cần sử dụng abs()với mô-đun%
99 Vấn đề - Cú pháp không phải là một

Chỉ dựa vào modulo vẫn sẽ để lại dấu hiệu tiêu cực. abs();loại bỏ các dấu hiệu tiêu cực đó là những gì tôi cần.
nxasdf

1

Một phiên bản thậm chí ngắn hơn cho các ngày trong tháng (tối đa 31) thay vì sử dụng mktime () và không yêu cầu pecl intl:

function ordinal($n) {
    return (new DateTime('Jan '.$n))->format('jS');
}

hoặc thủ tục:

echo date_format(date_create('Jan '.$n), 'jS');

Điều này tất nhiên hoạt động vì tháng mặc định tôi chọn (tháng 1) có 31 ngày.

Thật thú vị nếu bạn thử nó với tháng hai (hoặc một tháng khác mà không có 31 ngày), nó sẽ khởi động lại trước khi kết thúc:

...clip...
31st
1st
2nd
3rd

do đó bạn có thể đếm đến ngày của tháng này với công cụ xác định ngày ttrong vòng lặp của bạn: số ngày trong tháng.


1
function ordinal($number){

    $last=substr($number,-1);
    if( $last>3 || $last==0 || ( $number >= 11 && $number <= 19 ) ){
      $ext='th';
    }else if( $last==3 ){
      $ext='rd';
    }else if( $last==2 ){
      $ext='nd';
    }else{
      $ext='st';
    }
    return $number.$ext;
  }

0

Tìm thấy câu trả lời trong PHP.net

<?php
function ordinal($num)
{
    // Special case "teenth"
    if ( ($num / 10) % 10 != 1 )
    {
        // Handle 1st, 2nd, 3rd
        switch( $num % 10 )
        {
            case 1: return $num . 'st';
            case 2: return $num . 'nd';
            case 3: return $num . 'rd';  
        }
    }
    // Everything else is "nth"
    return $num . 'th';
}
?>

0

Đây là một phiên bản rất ngắn khác sử dụng các chức năng ngày. Nó hoạt động cho bất kỳ số nào (không bị hạn chế bởi các ngày trong tháng) và tính đến việc * 11th * 12th * 13 không tuân theo định dạng * 1 * 2 * 3.

function getOrdinal($n)
{
    return $n . date_format(date_create('Jan ' . ($n % 100 < 20 ? $n % 20 : $n % 10)), 'S');
}

-1

Tôi thích đoạn nhỏ này

<?php

  function addOrdinalNumberSuffix($num) {
    if (!in_array(($num % 100),array(11,12,13))){
      switch ($num % 10) {
        // Handle 1st, 2nd, 3rd
        case 1:  return $num.'st';
        case 2:  return $num.'nd';
        case 3:  return $num.'rd';
      }
    }
    return $num.'th';
  }

?>

ĐÂY


1
Tôi không chắc chắn những gì câu trả lời này cung cấp ngoài câu trả lời của ChintanThummar. Chà, gợi ý rằng ChintanThummar đã vi phạm bản quyền, trừ khi anh ta viết mã tại nguồn của bạn ...
Andreas Rejbrand 4/2/2015
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.