แสดงตัวเลขด้วยส่วนต่อท้ายอันดับใน PHP


149

ฉันต้องการแสดงตัวเลขดังนี้

  • 1 เป็นที่ 1
  • 2 เป็นที่ 2
  • ... ,
  • 150 เป็น 150

ฉันจะค้นหาคำต่อท้ายลำดับที่ถูกต้อง (st, nd, rd หรือ th) สำหรับแต่ละหมายเลขในรหัสของฉันได้อย่างไร


2
ดูคำตอบของฉันที่นี่ stackoverflow.com/questions/69262/…คำถามนั้นมีไว้สำหรับ. NET แต่ฉันตอบด้วยโซลูชัน PHP ดังนั้นควรช่วยคุณได้
nickf

วิธีเดียวที่ฉันคิดว่าทำสิ่งนี้คือมีคำสั่ง if ขึ้นสำหรับทุกหมายเลขที่คุณสามารถมีได้ IE ถ้า (1) จากนั้น "st" elseif (2) จากนั้น "nd" เป็นต้น ฯลฯ ถ้า (23000) " ครั้ง" มันเป็นปัญหาถ้าคุณมีตัวเลขขนาดใหญ่ แต่คุณสามารถเขียนโปรแกรมเพื่อเขียนรหัสให้กับคุณมันอาจวนซ้ำทุกตัวเลขที่พิมพ์ ifs เพื่อให้คุณคัดลอก + วางลงในรหัสของคุณ
Tom Gullen

2
@Tom ตารางการค้นหาอาจดีกว่าเพียงกำหนดค่าเริ่มต้นด้วยค่า 23000 และรับค่าที่ดัชนี n โดยที่ n คือหมายเลขที่คุณต้องการลำดับ
John Boker

2
พ.อ. กระสุน คุณอาจยอดเยี่ยม แต่ไม่ใช่ทั้งหมด ขอบคุณที่แสดงความสนใจในคำถามของฉัน
ArK

@John ความคิดที่ฉลาดมากมันจะเร็วมากในการเข้าถึงรวมถึงแต่ละดัชนีจะแสดงหมายเลขที่คุณค้นหา
Tom Gullen

คำตอบ:


283

จากวิกิพีเดีย :

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

ที่ไหน$numberเป็นหมายเลขที่คุณต้องการที่จะเขียน ทำงานร่วมกับจำนวนธรรมชาติใด ๆ

ในฐานะที่เป็นฟังก์ชั่น:

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

แม้ว่าในตอนแรกจะเข้าใจยาก แต่ตอนนี้ฉันคิดว่ามันเป็นวิธีที่ดีที่สุดที่แสดงให้เห็นว่าระบบคำต่อท้ายทำงานเป็นภาษาอังกฤษได้ดีที่สุด
erisco

6
ฉันชอบทางออกของคุณ นอกจากนี้หากคุณไม่ต้องการสร้างบรรทัดที่0 ให้แก้ไขบรรทัดสุดท้ายให้เป็น$abbreviation = ($number)? $number. $ends[$number % 10] : $number;
Gavin Jackson

1
@GavinJackson การเพิ่มโซลูชันที่ยอดเยี่ยมของคุณนี้ช่วยฉันได้จริงๆ (+1) คุณช่วยอธิบายให้ฉันฟังได้ว่าเกิดอะไรขึ้นในการคำนวณ? ฉันต้องการที่จะเข้าใจ ไชโย! แก้ไข: พบคำตอบ: ผู้ดำเนินการตามเงื่อนไข
Andrew Fox

ขออภัยต้องแบ่ง 111 คะแนนเป็น 112: D ทำให้เป็นฟังก์ชันใน Delphi พร้อมกับแอปตัวอย่าง: pastebin.com/wvmz1CHY
Jerry Dodge

1
@HafezDivandari - คุณแน่ใจนะ เพิ่งทดสอบกับ 7.1.19 และดูเหมือนว่าจะทำงานได้ดี
Iacopo

142

PHP มีในตัวฟังก์ชั่นสำหรับการนี้ มันยังรองรับความเป็นสากล!

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

โปรดทราบว่าฟังก์ชั่นนี้มีเฉพาะใน PHP 5.3.0 และใหม่กว่า


15
หมายเหตุสิ่งนี้ยังต้องใช้ PECL intl> = 1.0.0
rymo

4
คุณรู้หรือไม่ว่าเป็นไปได้ที่จะได้รับหมายเลขลำดับในรูปแบบคำ? เช่นที่หนึ่งที่สองที่สาม ฯลฯ แทน 1, 2, ที่ 3 ...
_

@ jeremy เมื่อฉันพยายามใช้ NumberFormatter มันจะพ่นข้อผิดพลาดNumberFomatter file not foundเสมอ คุณทำงานนี้ได้อย่างไร
jhnferraris

1
@Jhn คุณต้องติดตั้งส่วนขยายapt-get install php5-intl
Aley

@ ซอยฉันเห็น Yii มีฟอร์แมตเตอร์ในตัวที่เราใช้อยู่ตอนนี้ heh
jhnferraris

20

สามารถทำได้ในบรรทัดเดียวโดยใช้ประโยชน์จากฟังก์ชั่นที่คล้ายกันในฟังก์ชั่นวันที่ / เวลาของ PHP ฉันอ่อนน้อมถ่อมตน:

สารละลาย:

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

คำอธิบายโดยละเอียด:

date()ฟังก์ชันในตัวมีตรรกะต่อท้ายสำหรับการจัดการการคำนวณ nth-day-of-the-month ส่วนต่อท้ายจะถูกส่งคืนเมื่อSกำหนดในสตริงรูปแบบ:

date( 'S' , ? );

เนื่องจากdate()ต้องมีการประทับเวลา (สำหรับการ?ดังกล่าวข้างต้น) เราจะผ่านจำนวนเต็มของเรา$nเป็นdayพารามิเตอร์mktime()และการใช้หุ่นค่า1สำหรับhour, minute, secondและmonth:

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

สิ่งนี้ล้มเหลวได้อย่างงดงามในค่านอกช่วงสำหรับวันของเดือน (เช่น$n > 31) แต่เราสามารถเพิ่มตรรกะอินไลน์แบบง่าย ๆ เพื่อเพิ่ม$nที่ 29:

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

ค่าบวกเท่านั้น( พฤษภาคม 2017 ) สิ่งนี้ล้มเหลวคือ$n == 0แต่แก้ไขได้ง่ายโดยการเพิ่ม 10 ในกรณีพิเศษ:

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

อัปเดต, พฤษภาคม 2560

ตามที่สังเกตโดย @donatJ ข้อผิดพลาดข้างต้นล้มเหลวเกิน 100 (เช่น "111st") เนื่องจากการ>=20ตรวจสอบกลับคืนเป็นจริงเสมอ หากต้องการรีเซ็ตทุก ๆ ศตวรรษเราจะเพิ่มตัวกรองในการเปรียบเทียบ:

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

เพียงแค่ห่อไว้ในฟังก์ชั่นเพื่อความสะดวกและไม่ต้องไป!


14

นี่คือหนึ่งซับ:

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

อาจเป็นทางออกที่สั้นที่สุด แน่นอนสามารถห่อด้วยฟังก์ชั่น:

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

ขอแสดงความนับถือ Paul

EDIT1: การแก้ไขรหัสสำหรับ 11 ถึง 13

EDIT2: การแก้ไขโค้ดสำหรับ 111, 211, ...

แก้ไข 3: ตอนนี้มันทำงานได้อย่างถูกต้องเช่นกันสำหรับทวีคูณของ 10


ฉันชอบวิธีนี้ แต่อนิจจามันไม่ทำงาน :-( 30 ออกมาเป็น 30st 40 ออกมาเป็น 40st ฯลฯ
Flukey

1
ใช่ขอโทษ เมื่อฉันอ่านคำถามที่ฉันคิดว่าเฮ้นี่ควรเป็นไปได้ด้วยรหัสบรรทัดเดียว และฉันพิมพ์มันออกไป อย่างที่คุณเห็นจากการแก้ไขของฉันฉันกำลังปรับปรุง หลังจากแก้ไขครั้งที่สามตอนนี้ฉันคิดว่ามันค่อนข้างจะเสร็จแล้ว อย่างน้อยตัวเลขทั้งหมดตั้งแต่ 1 ถึง 150 พิมพ์ออกมาทางหน้าจอของฉัน
พอล

ดูดีมากถึง 500! (ยังไม่ได้ทดสอบมากกว่านั้น) การทำงานที่ดี! :-)
Flukey

13

จาก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

คำตอบที่ง่ายและสะดวกจะ:

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

//OUTPUT - rd

ไม่ได้พูดอะไรเกี่ยวกับวันที่ในคำถามสรรพสินค้า ฉันลงคะแนนแล้ว - เป็นวิธีแก้ปัญหาที่ง่ายและรวดเร็วเมื่อคุณรู้ว่าช่วงตัวเลขจะเป็น <32
cronoklee

8

ฉันเขียนสิ่งนี้สำหรับ PHP4 มันใช้งานได้ดีและมันค่อนข้างประหยัด

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 คุณช่วยขยาย / อธิบาย / อธิบายเพิ่มเติมอีกหน่อยได้ไหม? Tks!
iletras

4

คุณเพียงแค่ต้องใช้ฟังก์ชั่นที่กำหนด

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

โดยทั่วไปคุณสามารถใช้และเรียก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';
}
?>

2

ฉันสร้างฟังก์ชั่นที่ไม่พึ่งพาdate();ฟังก์ชั่นของ PHP เพราะมันไม่จำเป็น แต่ยังทำให้มันมีขนาดกะทัดรัดและสั้นที่สุดเท่าที่ฉันคิดว่าเป็นไปได้ในปัจจุบัน

รหัส : (รวม 121 ไบต์)

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

รหัสกระชับมากขึ้นด้านล่าง

มันทำงานได้ดังต่อไปนี้ :

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.

สิ่งที่ควรรู้เกี่ยวกับฟังก์ชั่นนี้ :

  • มันเกี่ยวข้องกับจำนวนเต็มลบเช่นเดียวกับจำนวนเต็มบวกและเก็บสัญญาณ
  • มันจะส่งกลับ 11, 12, 13, 811th, 812, 813, ฯลฯ สำหรับตัวเลขสิบสามตามที่คาดไว้
  • มันไม่ได้ตรวจสอบทศนิยม แต่จะปล่อยให้พวกเขาในสถานที่ (การใช้งานfloor($i), round($i)หรือceil($i)ที่จุดเริ่มต้นของคำสั่งคืนสุดท้าย)
  • คุณสามารถเพิ่มformat_number($i)ที่ต้นคำสั่งส่งคืนสุดท้ายเพื่อรับจำนวนเต็มคั่นด้วยเครื่องหมายจุลภาค (ถ้าคุณแสดงหลายพันล้าน ฯลฯ )
  • คุณสามารถลบออก$iจากจุดเริ่มต้นของคำสั่งส่งคืนถ้าคุณเพียงต้องการที่จะกลับคำต่อท้ายลำดับที่ไม่มีสิ่งที่คุณป้อน

ฟังก์ชั่นนี้ใช้งานได้เริ่มตั้งแต่ PHP 5.2 ที่เผยแพร่ในเดือนพฤศจิกายน 2549 หมดจดเพราะมีไวยากรณ์ของอาร์เรย์แบบสั้น หากคุณมีรุ่นก่อนหน้านี้โปรดอัปเกรดเพราะคุณเกือบจะล้าสมัย! ความล้มเหลวที่เพียงแทนที่ในบรรทัดกับตัวแปรชั่วคราวที่มี['st', 'nd', 'rd']array('st', 'nd', 'rd');

ฟังก์ชั่นเดียวกัน (โดยไม่ส่งคืนอินพุต) แต่เป็นมุมมองที่ขยายออกของฟังก์ชันสั้น ๆ ของฉันเพื่อความเข้าใจที่ดีขึ้น:

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
}

การปรับปรุงรหัส :

นี่คือเวอร์ชันที่แก้ไขซึ่งสั้นกว่า 14 ไบต์ (รวม 107 ไบต์):

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

หรือสั้นที่สุดเท่าที่จะเป็นไปได้คือ 25 ไบต์สั้นลง (รวม 96 ไบต์):

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

ด้วยฟังก์ชั่นสุดท้ายนี้เพียงแค่เรียกo(121);และมันก็จะเหมือนกับฟังก์ชั่นอื่น ๆ

การปรับปรุงรหัส # 2 :

เบ็นและฉันทำงานร่วมกันและตัดมันลง 38 ไบต์ (รวม 83 ไบต์):

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

เราไม่คิดว่ามันจะสั้นไปกว่านี้! อย่างไรก็ตามเต็มใจที่จะพิสูจน์ว่าผิด :)

หวังว่าทุกคนจะสนุก


คุณไม่จำเป็นต้องใช้abs()กับโมดูลัส%
99 ปัญหา - ไวยากรณ์ไม่ใช่หนึ่ง

การใช้งานโมดูโล่เท่านั้นจะยังคงมีเครื่องหมายลบอยู่ abs();ลบเครื่องหมายลบซึ่งเป็นสิ่งที่ฉันต้องการ
nxasdf

1

รุ่นที่สั้นลงสำหรับวันที่ในเดือน (สูงสุด 31) แทนที่จะใช้ mktime () และไม่ต้องการ pecl intl:

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

หรือขั้นตอน:

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

ใช้งานได้แน่นอนเพราะเดือนที่เริ่มต้นที่ฉันเลือก (มกราคม) มี 31 วัน

น่าสนใจพอถ้าคุณลองกับเดือนกุมภาพันธ์ (หรืออีกเดือนที่ไม่มี 31 วัน) มันจะรีสตาร์ทก่อนสิ้น:

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

ดังนั้นคุณสามารถนับได้ถึงวันของเดือนนี้ด้วยตัวระบุวันที่tในลูปของคุณ: จำนวนวันในเดือน


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

พบคำตอบใน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

นี่คืออีกเวอร์ชั่นสั้นมากโดยใช้ฟังก์ชั่นวันที่ มันทำงานได้กับตัวเลขใด ๆ (ไม่ จำกัด ตามวันของเดือน) และคำนึงถึงว่า * 11 * 12th * 13th ไม่เป็นไปตามรูปแบบ * 1 * 2 * 3

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

-1

ฉันชอบตัวอย่างเล็ก ๆ นี้

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

?>

ที่นี่


1
ฉันไม่แน่ใจว่าคำตอบนี้มีอะไรเพิ่มเติมนอกเหนือจากคำตอบของ ChintanThummar มันบ่งบอกว่า ChintanThummar ละเมิดลิขสิทธิ์เว้นแต่เขาจะเขียนโค้ดที่แหล่งข้อมูลของคุณ ...
Andreas Rejbrand
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.