在PHP中显示带序数后缀的数字


149

我想显示数字如下

  • 1为1,
  • 2作为第二
  • ...,
  • 150至150。

如何为代码中的每个数字找到正确的序数后缀(st,nd,rd或th)?


2
在这里查看我的答案。stackoverflow.com/questions/69262/…这个问题是针对.NET的,但是我回答了一个PHP解决方案,因此它应该可以为您提供帮助。
尼克

我能想到的唯一方法是在每个可能的数字上添加一个if语句,即IE,if(1),“ st”,elseif(2),“ nd”等,等等,如果(23000),然后“ nd”。如果您有很多数字,这是一个问题,但是您可以编写一个程序为您编写代码,它可以循环显示所有数字,打印ifs,供您复制+粘贴到您的代码中。
Tom Gullen

2
@Tom,查找表可能更好,只需使用23000值对其进行初始化,然后在索引n处获取该值,其中n是您想要的序数。
John Boker 2010年

2
弹片上校。您可能很聪明,但并非全部。无论如何,感谢您对我的问题表示关注
ArK 2010年

@John,这是一个非常聪明的主意,它将非常快速地访问,并且每个索引都代表您要查找的数字。
Tom Gullen

Answers:


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 2010年

6
我喜欢你的解决方案。此外,如果您不希望生成第0条,请将最后一行修改为$abbreviation = ($number)? $number. $ends[$number % 10] : $number;
Gavin Jackson

1
@GavinJackson您对这个出色解决方案的补充确实帮助了我(+1)。您能给我解释一下计算过程吗?我想了解 干杯! 编辑:找到了一个答案:有条件的运算符
安德鲁·福克斯

抱歉,必须将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 2012年

4
您知道能否以字词形式获取序号吗?即第一,第二,第三等,而不是第一,第二,第三...
its_me 2013年

@jeremy当我尝试使用NumberFormatter时,它始终会引发错误NumberFomatter file not found。您是如何解决的?
jhnferraris 2014年

1
@Jhn,您必须安装扩展程序apt-get install php5-intl
Aley

@Aley,我明白了。Yii有一个内置的格式化程序,我们现在正在使用。嘿
jhnferraris '16

20

通过利用PHP内置的日期/时间函数中的类似功能,可以在一行中完成此操作。我谦虚地提交:

解:

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

详细说明:

内置date()函数具有后缀逻辑,用于处理每月第n天的计算。当S以格式字符串给出时,返回后缀:

date( 'S' , ? );

由于date()需要的时间戳(对于?以上),我们将通过我们的整数$n作为day参数mktime()和使用假人值1hourminutesecond,和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年5月)失败的原因是$n == 0,但通过在特殊情况下添加10可以轻松解决:

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

更新,2017年5月

如@donatJ所观察到的那样,由于>=20检查始终返回true ,因此上述结果在100以上(例如“ 111st”)失败。要在每个世纪重置这些值,我们在比较中添加一个过滤器:

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

问候,保罗

EDIT1:11到13的代码更正。

EDIT2:111、211,...的代码更正

EDIT3:现在它也可以正常工作10的倍数。


我喜欢这种方法,但很可惜,它不工作:-( 30日出来为30日以上40出来的40st等。
Flukey

1
是的,对不起。当我阅读我认为的问题时,嘿,应该可以通过一行代码来实现。我只是把它打掉了。正如您从我的修改中看到的那样,我正在进步。现在进行第三次编辑后,我认为它已经完成了。至少从1到150的所有数字都能在我的屏幕上很好地打印出来。
保罗2010年

看起来高达500!(没有进一步测试过)。干得好!:-)
Flukey 2010年

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 '17

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

我制作了一个函数,该函数不依赖于PHP的date();函数,因为它不是必需的,而且使它变得紧凑且尽可能短,因为我认为这是当前可能的。

代码:(总共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日,第811,812th,813th等-teen预期数字。
  • 它不检查小数,但将它们留在地方(使用floor($i)round($i)ceil($i)在最后的return语句的开始)。
  • 您还可以format_number($i)在最终return语句的开头添加以逗号分隔的整数(如果要显示成千上万个,等等)。
  • $i如果只想返回没有输入内容的序数后缀,则可以只从return语句的开头删除。

该函数从2006年11月发布的PHP 5.2开始就完全起作用,这完全是由于数组语法较短。如果您之前有版本,请升级,因为您已经过时了将近十年!失败的话,只需将内联替换为['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

Ben和我一起工作,将其减少了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 '16

1

一个月中日期的更短版本(最多31个),而不是使用mktime()并且不需要pecl intl:

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

或程序上:

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

这当然有效,因为我选择的默认月份(一月)为31天。

有趣的是,如果您在2月(或另一个不包含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 * 12 * 13th不遵循* 1 * 2nd * 3rd格式。

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 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.