Menampilkan angka dengan akhiran ordinal dalam PHP

149

Saya ingin menampilkan angka sebagai berikut

  • 1 sebagai 1,
  • 2 sebagai 2,
  • ...,
  • 150 sebagai 150.

Bagaimana saya menemukan sufiks ordinal yang benar (st, nd, rd atau th) untuk setiap nomor dalam kode saya?

Tabut
sumber
2
Lihat jawaban saya di sini. stackoverflow.com/questions/69262/... Pertanyaan itu untuk .NET, tapi saya jawab dengan solusi PHP, jadi itu akan membantu Anda.
nickf
Satu-satunya cara saya bisa memikirkan melakukan ini adalah memiliki pernyataan if naik untuk setiap nomor yang mungkin Anda miliki, yaitu, jika (1) lalu "st" elseif (2) lalu "nd" dll dll jika (23000) maka " nd ". Ini masalah jika Anda memiliki angka besar tetapi Anda bisa menulis sebuah program untuk menulis kode untuk Anda, itu bisa mengulang semua angka mencetak ifs bagi Anda untuk menyalin + menempelkan ke kode Anda.
Tom Gullen
2
@ Tom, tabel pencarian mungkin lebih baik, cukup inisialisasi dengan nilai 23000 dan dapatkan nilai di indeks n, di mana n adalah angka yang Anda inginkan ordinal.
John Boker
2
Kolonel pecahan peluru. Anda mungkin brilian tetapi tidak semua. terima kasih karena telah menunjukkan minat pada pertanyaan saya
ArK
@ John, ide yang sangat pintar, itu akan sangat cepat diakses dan setiap indeks mewakili nomor yang Anda cari.
Tom Gullen

Jawaban:

283

dari 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];

Di mana $numbernomor yang ingin Anda tulis. Bekerja dengan bilangan alami apa pun.

Sebagai fungsi:

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);
Iacopo
sumber
Meskipun agak sulit untuk dipahami pada awalnya, saya sekarang berpikir itu yang terbaik mewakili bagaimana sistem sufiks ordinal bekerja untuk bahasa Inggris.
erisco
6
Saya suka solusi Anda. Selain itu, jika Anda memilih untuk tidak menghasilkan 0, ubah baris terakhir menjadi$abbreviation = ($number)? $number. $ends[$number % 10] : $number;
Gavin Jackson
1
@ GavinJackson, penambahan Anda ke solusi luar biasa ini sangat membantu saya (+1). Bisakah Anda jelaskan kepada saya apa yang terjadi dalam perhitungan? Aku ingin mengerti. Bersulang! EDIT: Menemukan jawaban: operator kondisional
Andrew Fox
Maaf, harus memecah 111 suara menjadi 112: D Membuatnya berfungsi di Delphi bersama dengan aplikasi demo: pastebin.com/wvmz1CHY
Jerry Dodge
1
@HafezDivandari - Anda yakin? Baru diuji dengan 7.1.19 dan sepertinya berfungsi dengan baik
Iacopo
142

PHP memiliki fungsi bawaan untuk ini . Ia bahkan menangani internasionalisasi!

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

Perhatikan bahwa fungsi ini hanya tersedia di PHP 5.3.0 dan yang lebih baru.

Jeremy Kauffman
sumber
15
Perhatikan ini juga membutuhkan PECL intl> = 1.0.0
rymo
4
Apakah Anda tahu apakah mungkin untuk mendapatkan nomor urut dalam bentuk kata? yaitu pertama, kedua, ketiga, dll, bukannya 1, 2, 3 ...
its_me
@ Jeremy Ketika saya mencoba menggunakan NumberFormatter, selalu ada kesalahan itu NumberFomatter file not found. Bagaimana Anda mengatasi ini?
jhnferraris
1
@Jhn Anda harus menginstal ekstensiapt-get install php5-intl
Aley
@Aku mengerti. Yii memiliki pemformat bawaan yang kami gunakan saat ini. heh
jhnferraris
20

Ini dapat dicapai dalam satu baris dengan memanfaatkan fungsionalitas yang serupa dalam fungsi tanggal / waktu bawaan PHP. Dengan rendah hati saya serahkan:

Larutan:

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

Penjelasan detail:

Built-in date()fungsi memiliki logika akhiran untuk menangani n-hari-of-the-bulan perhitungan. Suffix dikembalikan ketika Sdiberikan dalam format string:

date( 'S' , ? );

Sejak date()membutuhkan timestamp (untuk ?di atas), kita akan melewati bilangan bulat kami $nsebagai dayparameter untuk mktime()dan penggunaan boneka nilai 1untuk hour, minute, second, dan month:

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

Ini sebenarnya gagal dengan anggun pada nilai di luar rentang untuk hari dalam sebulan (yaitu $n > 31) tetapi kita dapat menambahkan beberapa logika sebaris sederhana untuk ditutup $npada 29:

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

Satu-satunya nilai positif( Mei 2017 ) ini gagal pada $n == 0, tapi itu mudah diperbaiki dengan menambahkan 10 dalam kasus khusus:

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

Pembaruan, Mei 2017

Seperti yang diamati oleh @donatJ, hal di atas gagal di atas 100 (misalnya "111"), karena >=20cek selalu kembali benar. Untuk mengatur ulang ini setiap abad, kami menambahkan filter ke perbandingan:

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

Hanya membungkusnya dalam fungsi untuk kenyamanan dan pergilah!

Andrew Kozak
sumber
14

Berikut ini adalah one-liner:

$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);

Mungkin solusi terpendek. Tentu saja dapat dibungkus dengan fungsi:

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

Salam, Paul

EDIT1: Koreksi kode untuk 11 hingga 13.

EDIT2: Koreksi kode untuk 111, 211, ...

EDIT3: Sekarang berfungsi dengan benar juga untuk kelipatan 10.

Paul
sumber
Saya suka pendekatan ini, tapi sayangnya, itu tidak berhasil :-( 30 keluar sebagai 30. 40 keluar sebagai 40. dll.
Flukey
1
Ya maaf Ketika saya membaca pertanyaan yang saya pikir, hei ini harus dimungkinkan oleh satu baris kode. Dan saya baru saja mengetiknya. Seperti yang Anda lihat dari suntingan saya, saya membaik. Setelah edit ketiga sekarang saya pikir sudah cukup. Setidaknya semua angka dari 1 hingga 150 dicetak dengan baik di layar saya.
Paul
Terlihat bagus hingga 500! (belum diuji lebih jauh dari itu). Kerja bagus! :-)
Flukey
13

dari 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;
}
?> 
John Boker
sumber
9

Jawaban yang Sederhana dan Mudah adalah:

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

//OUTPUT - rd
Kuda putih
sumber
Tidak mengatakan apa pun tentang tanggal dalam pertanyaan itu. Saya tetap terpilih - ini adalah solusi cepat dan sederhana ketika Anda tahu kisaran nomor akan menjadi <32
cronoklee
8

Saya menulis ini untuk PHP4. Sudah bekerja dengan baik & cukup ekonomis.

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';  
}
iletras
sumber
Vishal Kumar, bisakah kamu memperluas / menjelaskan / menjelaskan itu sedikit lebih? Tks!
iletras
4

Anda hanya perlu menerapkan fungsi yang diberikan.

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';
}
Chintan Thummar
sumber
3

Secara umum, Anda dapat menggunakannya dan memanggil echo get_placing_string (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';
}
?>
Uzair Bin Nisar
sumber
2

Saya membuat fungsi yang tidak bergantung pada fungsi PHP date();karena tidak perlu, tetapi juga membuatnya sebagai kompak dan sesingkat yang saya pikir saat ini mungkin.

Kode : (total 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')));
}

Lebih banyak kode ringkas di bawah ini.

Ia bekerja sebagai berikut :

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.

Hal yang perlu diketahui tentang fungsi ini :

  • Ini berkaitan dengan bilangan bulat negatif sama dengan bilangan bulat positif dan menyimpan tanda.
  • Ini mengembalikan 11, 12, 13, 811, 812, 813, dll untuk angka -teen seperti yang diharapkan.
  • Tidak memeriksa desimal, tetapi akan meninggalkan mereka di tempat (gunakan floor($i), round($i)atau ceil($i)pada awal pernyataan kembali akhir).
  • Anda juga bisa menambahkan format_number($i)di awal pernyataan pengembalian akhir untuk mendapatkan integer yang dipisahkan koma (jika Anda menampilkan ribuan, jutaan, dll.).
  • Anda bisa menghapus $idari awal pernyataan kembali jika Anda hanya ingin mengembalikan akhiran ordinal tanpa apa yang Anda input.

Fungsi ini berfungsi mulai PHP 5.2 yang dirilis November 2006 murni karena sintaks array pendek. Jika Anda memiliki versi sebelum ini, silakan tingkatkan karena Anda hampir satu dekade kedaluwarsa! Gagal itu, ganti saja in-line ['st', 'nd', 'rd']dengan variabel sementara yang berisi array('st', 'nd', 'rd');.

Fungsi yang sama (tanpa mengembalikan input), tetapi pandangan meledak dari fungsi pendek saya untuk pemahaman yang lebih baik:

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
}

Pembaruan Kode :

Berikut ini adalah versi modifikasi yang lebih pendek 14 byte penuh (total 107 byte):

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

Atau untuk sesingkat mungkin menjadi 25 byte lebih pendek (total 96 byte):

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

Dengan fungsi terakhir ini, cukup panggil o(121);dan itu akan melakukan persis sama dengan fungsi lain yang saya daftarkan.

Pembaruan Kode # 2 :

Ben dan saya bekerja bersama dan memotongnya sebesar 38 byte (total 83 byte):

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

Kami tidak berpikir itu bisa lebih pendek dari ini! Bersedia terbukti salah, namun. :)

Semoga kalian semua menikmati.

nxasdf
sumber
Anda tidak perlu menggunakan abs()modulus%
99 Masalah - Sintaksis bukan satu
Mengandalkan modulo saja masih akan meninggalkan tanda negatif di tempatnya. abs();menghilangkan tanda negatif yang saya butuhkan.
nxasdf
1

Versi yang lebih pendek untuk tanggal di bulan (hingga 31) alih-alih menggunakan mktime () dan tidak memerlukan pecl intl:

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

atau secara prosedural:

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

Ini tentu saja berfungsi karena bulan default yang saya pilih (Januari) memiliki 31 hari.

Cukup menarik jika Anda mencobanya dengan Februari (atau bulan lain tanpa 31 hari), itu dimulai lagi sebelum akhir:

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

jadi Anda bisa menghitung hingga hari-hari bulan ini dengan penentu tanggal tdi loop Anda: jumlah hari dalam sebulan.

Dan Dart
sumber
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;
  }
xyz
sumber
0

Menemukan jawaban di 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';
}
?>
mistik
sumber
0

Berikut ini adalah versi yang sangat singkat menggunakan fungsi tanggal. Ini bekerja untuk nomor berapa pun (tidak dibatasi oleh hari dalam sebulan) dan memperhitungkan bahwa * 11 * 12 * 13 tidak mengikuti format * 1 * 2 * 3.

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

Saya suka potongan kecil ini

<?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';
  }

?>

SINI

niksmac
sumber
1
Saya tidak yakin apa yang ditawarkan jawaban ini selain jawaban ChintanThummar. Nah, itu mengisyaratkan bahwa ChintanThummar membuat pelanggaran hak cipta, kecuali dia menulis kode di sumber Anda ...
Andreas Rejbrand