Я хочу отображать числа следующим образом
- 1 как 1-й,
- 2 как 2-й,
- ...
- 150 как 150-е.
Как мне найти правильный порядковый суффикс (st, nd, rd или th) для каждого номера в моем коде?
Я хочу отображать числа следующим образом
Как мне найти правильный порядковый суффикс (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 и более поздних версиях.
Это можно выполнить в одной строке, используя аналогичные функции встроенных функций времени и времени 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
всегда возвращают true. Для reset в каждом столетии мы добавляем фильтр к сравнению:
date( 'S', mktime( 1, 1, 1, 1, ( (($n>=10)+($n%100>=20)+($n==0))*10 + $n%10) ));
Просто оберните его в функцию для удобства и отпустите!
из 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.
Я написал это для 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';
}
Я сделал функцию, которая не полагается на функцию 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.
Знать об этой функции:
floor($i)
, round($i)
или ceil($i)
в начале конечного оператора return).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:
Ben, и я работал вместе и сокращал его на 38 байт (всего 83 байта):
function o($i){[email protected](($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() и не требует 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
в вашем цикле: количество дней в месяце.
Чтобы упростить ответ 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];
}
Edit
Моя выше функция, кажется, терпит неудачу для чисел, заканчивающихся на 11, 12, 13, которые я не заметил при отправке ответа. Поэтому используйте ответ Lacopo.
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;
}
Здесь еще одна очень короткая версия, использующая функции даты. Он работает для любого числа (не ограниченного днями месяца) и учитывает, что * 11th * 12th * 13th не следует * 1-го * 2-го * 3-го формата.
function getOrdinal($n)
{
return $n . date_format(date_create('Jan ' . ($n % 100 < 20 ? $n % 20 : $n % 10)), 'S');
}
Я люблю этот небольшой фрагмент
<?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';
}
?>