【问题标题】:Display numbers with ordinal suffix in PHP在 PHP 中显示带序号后缀的数字
【发布时间】:2011-03-07 19:14:56
【问题描述】:

我想如下显示数字

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

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

【问题讨论】:

  • 在这里查看我的答案。 stackoverflow.com/questions/69262/… 这个问题是针对 .NET 的,但我用 PHP 解决方案回答,所以它应该可以帮助你。
  • 我能想到的唯一方法是为每个可能拥有的数字增加一个 if 语句,即,如果(1)然后“st” elseif(2)然后“nd”等如果(23000)然后“nd”。如果您的数字很大,但您可以编写一个程序来为您编写代码,这将是一个问题,它可以循环打印所有数字,以便您将 ifs 复制并粘贴到您的代码中。
  • @Tom,查找表可能会更好,只需使用 23000 个值初始化它并获取索引 n 处的值,其中 n 是您想要的序数。
  • 上校。弹片。你可能很聪明,但不是全部。无论如何感谢您对我的问题表现出兴趣
  • @John,非常聪明的主意,访问起来会非常快,而且每个索引都代表您正在查找的数字。

标签: php numbers


【解决方案1】:

来自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;
}
?> 

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

    • 虽然一开始有点难理解,但我现在认为它最能代表英语的序数后缀系统。
    • 我喜欢你的解决方案。此外,如果您不想生成 0th,请将最后一行修改为 $abbreviation = ($number)? $number. $ends[$number % 10] : $number;
    • @GavinJackson 您对这个出色解决方案的添加确实帮助了我(+1)。您能否向我解释一下计算中发生了什么?我想明白。干杯!编辑:找到答案:conditional operator
    • 抱歉,不得不将 111 票改为 112 票:D 在 Delphi 中将其作为一个函数以及一个演示应用程序:pastebin.com/wvmz1CHY
    • @HafezDivandari - 你确定吗?刚刚用 7.1.19 测试过,似乎工作正常
    【解决方案3】:

    这是一个单行:

    $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 的倍数。

    【讨论】:

    • 我喜欢这种方法,但是很可惜,它不起作用:-( 30th 出现在 30st 中。40th 出现在 40st 中。等等。
    • 是的,对不起。当我读到我想的问题时,嘿,这应该可以通过一行代码来实现。我只是把它打掉了。正如你从我的编辑中看到的,我正在改进。在第三次编辑之后,我认为它已经完成了。至少从 1 到 150 的所有数字都可以在我的屏幕上很好地打印出来。
    • 高达 500 看起来不错! (还没有进一步测试它)。干得好! :-)
    【解决方案4】:

    PHP has built-in functionality for this。它甚至可以处理国际化!

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

    请注意,此功能仅在 PHP 5.3.0 及更高版本中可用。

    【讨论】:

    • 注意这也需要PECL intl >= 1.0.0
    • 你知道是否可以得到word形式的序数?即第一,第二,第三等,而不是第一,第二,第三......
    • @jeremy 当我尝试使用 NumberFormatter 时,它总是会抛出 NumberFomatter file not found 的错误。你是如何解决这个问题的?
    • @Jhn 你必须安装扩展apt-get install php5-intl
    • @Aley 我明白了。 Yii 有一个我们现在正在使用的内置格式化程序。呵呵
    【解决方案5】:

    我为 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,您能否进一步扩展/解释/解释一下?谢了!
    【解决方案6】:

    这可以通过利用 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(),并为hour 使用虚拟值1minutesecondmonth

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

    这实际上在一个月中某天的值超出范围时会正常失败(即$n &gt; 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”),因为&gt;=20 检查总是返回 true。为了在每个世纪重置这些,我们在比较中添加了一个过滤器:

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

    为方便起见,只需将其包装在一个函数中即可!

    【讨论】:

      【解决方案7】:

      通常,您可以使用它并调用 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';
      }
      ?>
      

      【讨论】:

        【解决方案8】:

        你只需要应用给定的功能。

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

        【讨论】:

          【解决方案9】:

          我喜欢这个小sn-p

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

          HERE

          【讨论】:

          • 除了 ChintanThummar 的答案之外,我不太确定这个答案提供了什么。好吧,它暗示 ChintanThummar 侵犯了版权,除非他在您的源代码处编写了代码...
          【解决方案10】:

          我制作了一个不依赖于 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.
          

          有关此功能的知识

          • 它处理负整数与正整数一样,并保留符号。
          • 它按预期返回 -teen 数字的第 11、12、13、811、812、813 等。
          • 它不检查小数,但会保留它们(在最终返回语句的开头使用 floor($i)round($i)ceil($i))。
          • 您还可以在最后的 return 语句的开头添加 format_number($i) 以获得逗号分隔的整数(如果您要显示数千、数百万等)。
          • 如果您只想在不输入任何内容的情况下返回序数后缀,则只需从 return 语句的开头删除 $i

          这个函数从 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()和模数%
          • 仅依赖模数仍会保留负号。 abs(); 删除了我需要的负号。
          【解决方案11】:

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

          【讨论】:

            【解决方案12】:

            一个更短的月份日期版本(最多 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 来计算本月的天数:该月的天数。

            【讨论】:

              【解决方案13】:

              简单易行的答案是:

              $Day = 3; 
              echo date("S", mktime(0, 0, 0, 0, $Day, 0));
              
              //OUTPUT - rd
              

              【讨论】:

              • 对问题中的日期没有说任何话。无论如何我都赞成 - 当您知道数字范围将是 时,这是一个快速简单的解决方案
              【解决方案14】:
              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;
                }
              

              【讨论】:

                【解决方案15】:

                这是另一个使用日期函数的非常简短的版本。它适用于任何数字(不受月份天数的限制),并考虑到 *11th *12th *13th 不遵循 *1st *2nd *3rd 格式。

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

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2020-06-08
                  • 2013-06-12
                  • 1970-01-01
                  • 1970-01-01
                  • 2012-03-02
                  • 1970-01-01
                  • 2020-05-09
                  • 1970-01-01
                  相关资源
                  最近更新 更多