Отображать номера с порядковым суффиксом в PHP

Я хочу отображать числа следующим образом

  • 1 как 1-й,
  • 2 как 2-й,
  • …,
  • 150 – 150.

Как я должен найти правильный порядковый суффикс (st, nd, rd или th) для каждого числа в моем коде?

из Википедии :

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

PHP имеет встроенные функции для этого . Он даже обрабатывает интернационализацию!

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

Обратите внимание, что эта функция доступна только в PHP 5.3.0 и более поздних версиях.

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

Вот однострочный:

 $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.

Это можно сделать в одной строке, используя аналогичные функции встроенных функций времени и времени 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) )); 

Обновление, май 2017 г.

Как отмечено @donatJ, выше вышло не более 100 (например, «111st»), так как проверки >=20 всегда верны. Чтобы сбросить их каждый век, добавим фильтр к сравнению:

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

Просто оберните его в функцию для удобства и от вас!

Я написал это для 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'; } 

Простым и легким ответом будет:

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

В общем случае вы можете использовать это и вызвать 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'; } ?> 

вам просто нужно применить данную функцию.

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

Я сделал функцию, которая не полагается на date(); 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, 811th, 812th, 813th и т. Д. Для 15 чисел, как ожидалось.
  • Он не проверяет десятичные знаки, но оставит их на месте (используйте floor($i) , round($i) или ceil($i) в начале окончательного оператора возврата).
  • Вы также можете добавить format_number($i) в начале конечного оператора return, чтобы получить целое число, разделенное запятыми (если вы показываете тысячи, миллионы и т. Д.).
  • Вы можете просто удалить $i с начала оператора return, если хотите только вернуть порядковый суффикс без ввода.

Эта функция работает начиная с PHP 5.2, выпущенного в ноябре 2006 года исключительно из-за синтаксиса короткого массива. Если у вас есть версия до этого, пожалуйста, обновите, потому что вы почти десятилетие устарели! В противном случае просто замените в строке ['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);} 

Мы не думаем, что это может стать короче этого! Тем не менее, желая доказать свою правоту. 🙂

Надеюсь, вам понравится.

Найден ответ в 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'; } ?> 

Еще более короткая версия для дат в месяце (до 31) вместо использования mktime () и не требующая int int:

 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 в вашем цикле: количество дней в месяце.

Чтобы еще больше упростить ответ Lacopo, вы можете использовать следующую функцию, которая получает последнюю цифру числа с помощью функции substr () и использует ее как индекс $ end array.

 function get_ordinal($number) { $ends=array('th','st','nd','rd','th','th','th','th','th','th'); $last_digit=substr($number, -1, 1); return $number.$ends[$last_digit]; } 

редактировать

Моя функция выше, кажется, терпит неудачу для чисел, заканчивающихся на 11, 12, 13, которые я не заметил при публикации ответа. Поэтому воспользуйтесь ответом Лакопо.

Я люблю этот небольшой фрагмент

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

ВОТ