在PHP中显示具有序数后缀的数字

180

我希望以以下方式显示数字

  • 将1显示为1st,
  • 将2显示为2nd,
  • ......
  • 将150显示为150th。

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


2
请看我在这里的回答。https://dev59.com/mnVD5IYBdhLWcg3wKYL-#69284 那个问题是关于.NET的,但我用PHP解决了它,所以它应该对你有帮助。 - nickf
我能想到的唯一方法是为每个可能存在的数字设置一个 if 语句,例如 if(1) then "st" elseif (2) then "nd" 等等,如果 (23000) then "nd"。如果你有很大的数字,这会成为一个问题,但你可以编写一个程序为你编写代码,它可以循环所有数字打印 ifs,以便复制+粘贴到你的代码中。 - Tom Gullen
2
@Tom,使用查找表可能更好,只需使用23000个值进行初始化,并获取索引n处的值,其中n是您想要的序数。 - John Boker
2
Shrapnel校官,您可能很出色,但并非全部。无论如何,感谢您对我的问题表示关注。 - ArK
看看这篇文章。那里的函数是有效的 https://kitson-consulting.co.uk/blog/php-code-add-st-nd-rd-or-th-number - Junior
显示剩余3条评论
17个回答

328

来自维基百科:

$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
7
我喜欢你的解决方案。此外,如果您不想生成第0个修改,请将最后一行修改为$abbreviation = ($number)? $number. $ends[$number % 10] : $number; - Gavin Jackson
1
@GavinJackson 你对这个优秀解决方案的贡献真的帮了我很多(+1)。可以请你解释一下计算中正在发生的事情吗?我想要理解。谢谢! 编辑:找到答案:条件运算符. - Andrew Fox
抱歉,不得不将111票打破到112票 :D 我在Delphi中制作了一个函数以及一个演示应用程序:http://pastebin.com/wvmz1CHY - Jerry Dodge
1
@HafezDivandari - 你确定吗?我刚测试了7.1.19,看起来运行良好。 - Iacopo
显示剩余3条评论

186

PHP内置此功能,甚至支持国际化!

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

请注意,此功能仅适用于PHP 5.3.0及更高版本。


18
请注意,这还需要 PECL intl >= 1.0.0。 - rymo
4
你知道是否可能以文字形式获取序数词?例如:first,second,third等,而不是1st,2nd,3rd ... - its_me
@jeremy 当我尝试使用NumberFormatter时,它总是抛出一个错误,指出NumberFomatter文件未找到。你是如何解决这个问题的? - jhnferraris
1
@Jhn 你需要安装扩展名 apt-get install php5-intl - Aley
@Aley 我明白了。Yii现在有一个内置的格式化程序,我们正在使用它。嘿 - jhnferraris

26

通过利用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(),并使用1作为hourminutesecondmonth的虚拟值:

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所观察到的那样,上述代码在超过100(例如"111st")时会失败,因为>=20的检查总是返回true。为了每个世纪重置这些值,我们向比较添加了一个过滤器:

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

只需将其包装在一个函数中以方便使用,然后就可以开始了!


这对大于31的数字有效吗? - Popnoodles
@Popnoodles 你告诉我:https://onlinephp.io/c/f6246 [onlinephp.io沙盒] - Andrew Kozak

16

这是一行代码:

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

问候,保罗

编辑1:修正11到13的代码。

编辑2:修正111、211等代码。

编辑3:现在它也可以正确处理10的倍数。


我喜欢这种方法,但遗憾的是它不起作用 :-(30th会出现为30st。40th会出现为40st。等等。 - Flukey
1
是的,抱歉。当我看到这个问题时,我想,嘿,这应该可以用一行代码实现。然后我就打了出来。正如您从我的编辑中看到的那样,我正在改进。经过第三次编辑,我认为它已经完成了。至少在我的屏幕上,从1到150的所有数字都可以很好地打印出来。 - Paul
看起来在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;
}
?> 

11

简单明了的答案是:

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

//OUTPUT - rd

1
问题中并没有提到日期。不过我还是点了赞——当你知道数字范围小于32时,这是一个快速简单的解决方案。 - cronoklee
1
OP希望这个能够至少支持到150。而你的代码在32天时就会出现问题,因为0/32/0000会被转换成12/32/-0001,然后滚动到1/1/0000,意味着第32天变成了第1天并且加上了“st”。正如@cronoklee所说,它可以处理31及以下的数字,但这不是OP所要求的。 - Stevish

9

这是我为 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,你能再详细解释一下吗?谢谢! - iletras
2
我知道有点晚了,但是回答@iletras的问题,这个函数首先获取数字的模100(除以100,返回余数,有效地删除百位及以上的所有内容),并将其放入$number变量中。然后它获取最后一位数字,并将其放入$lastChar中。由于大多数情况下需要在末尾加上“th”,因此它只关注特殊情况:以1、2或3结尾的数字。在每种情况下,该函数寻找例外情况(11、12和13)以在这些情况下返回“th”,或者对于其他所有情况返回“st”、“nd”或“rd”。我个人认为这个函数是最好的。 - Stevish

4

这是正确的解决方案。

$numberFormatter = new NumberFormatter('en_US', NumberFormatter::ORDINAL);

echo $numberFormatter->format(11);

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接