Chcę wyświetlić liczby w następujący sposób
- 1 jako 1,
- 2 jako 2,
- ...,
- 150 jako 150.
Jak znaleźć poprawny przyrostek porządkowy (st, nd, rd lub th) dla każdej liczby w moim kodzie?
Chcę wyświetlić liczby w następujący sposób
Jak znaleźć poprawny przyrostek porządkowy (st, nd, rd lub th) dla każdej liczby w moim kodzie?
Odpowiedzi:
$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];
Gdzie $number
jest numer, który chcesz wpisać. Działa z dowolną liczbą naturalną.
Jako funkcja:
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);
$abbreviation = ($number)? $number. $ends[$number % 10] : $number;
PHP ma do tego wbudowaną funkcjonalność . Obsługuje nawet internacjonalizację!
$locale = 'en_US';
$nf = new NumberFormatter($locale, NumberFormatter::ORDINAL);
echo $nf->format($number);
Zauważ, że ta funkcja jest dostępna tylko w PHP 5.3.0 i nowszych.
NumberFomatter file not found
. Jak sobie z tym poradziłeś?
apt-get install php5-intl
Można to osiągnąć w jednym wierszu, wykorzystując podobną funkcjonalność wbudowanych funkcji daty / czasu PHP. Pokornie poddaję się:
Rozwiązanie:
function ordinalSuffix( $n )
{
return date('S',mktime(1,1,1,1,( (($n>=10)+($n>=20)+($n==0))*10 + $n%10) ));
}
Szczegółowe wyjaśnienie:
Wbudowana date()
funkcja ma logikę sufiksu do obsługi obliczeń n-tego dnia miesiąca. Sufiks jest zwracany, gdy S
jest podany w ciągu formatu:
date( 'S' , ? );
Ponieważ date()
wymaga znacznika czasu (dla ?
powyżej), będziemy przechodzić naszą całkowitą $n
jako day
parametr mktime()
i wykorzystania manekina wartości 1
dla hour
, minute
, second
, i month
:
date( 'S' , mktime( 1 , 1 , 1 , 1 , $n ) );
To faktycznie kończy się niepowodzeniem w przypadku wartości spoza zakresu dla dnia miesiąca (tj. $n > 31
), Ale możemy dodać prostą logikę wbudowaną do ograniczenia $n
do 29:
date( 'S', mktime( 1, 1, 1, 1, ( (($n>=10)+($n>=20))*10 + $n%10) ));
Jedyna wartość dodatnia( Maj 2017 ) to nie działa $n == 0
, ale można to łatwo naprawić, dodając 10 w tym specjalnym przypadku:
date( 'S', mktime( 1, 1, 1, 1, ( (($n>=10)+($n>=20)+($n==0))*10 + $n%10) ));
Aktualizacja, maj 2017
Jak zauważył @donatJ, powyższe zawodzi powyżej 100 (np. „111st”), ponieważ >=20
sprawdzenia zawsze zwracają prawdę. Aby zresetować je co stulecie, dodajemy filtr do porównania:
date( 'S', mktime( 1, 1, 1, 1, ( (($n>=10)+($n%100>=20)+($n==0))*10 + $n%10) ));
Po prostu zapakuj go w funkcję dla wygody i gotowe!
Oto jedna linijka:
$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);
Prawdopodobnie najkrótsze rozwiązanie. Oczywiście można ją opakować funkcją:
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);
}
Pozdrawiam, Paul
EDIT1: Korekta kodu od 11 do 13.
EDIT2: Korekta kodu dla 111, 211, ...
EDIT3: Teraz działa poprawnie również dla wielokrotności 10.
z 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;
}
?>
Napisałem to dla PHP4. Działa dobrze i jest dość ekonomiczne.
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';
}
wystarczy zastosować daną funkcję.
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';
}
Generalnie możesz tego użyć i wywołać 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';
}
?>
Zrobiłem funkcję, która nie opiera się na funkcji PHP, date();
ponieważ nie jest to konieczne, ale także uczyniłem ją tak zwartą i tak krótką, jak myślę, że jest obecnie możliwa.
Kod : (łącznie 121 bajtów)
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')));
}
Bardziej zwarty kod poniżej.
Działa w następujący sposób :
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.
Co warto wiedzieć o tej funkcji :
floor($i)
, round($i)
lub ceil($i)
na początku końcowego instrukcji return).format_number($i)
na początku ostatniej instrukcji return, aby uzyskać liczbę całkowitą oddzieloną przecinkami (jeśli wyświetlasz tysiące, miliony itp.).$i
z początku instrukcji return, jeśli chcesz zwrócić tylko przyrostek porządkowy bez tego, co wprowadzisz.Ta funkcja działa od wersji PHP 5.2 wydanej w listopadzie 2006 wyłącznie z powodu składni krótkich tablic. Jeśli masz wersję wcześniejszą, zaktualizuj ją, ponieważ jesteś prawie dziesięć lat nieaktualny! Jeśli to się nie uda, po prostu zamień in-line ['st', 'nd', 'rd']
na tymczasową zmienną zawierającą array('st', 'nd', 'rd');
.
Ta sama funkcja (bez zwracania danych wejściowych), ale rozstrzelony widok mojej krótkiej funkcji dla lepszego zrozumienia:
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
}
Aktualizacja kodu :
Oto zmodyfikowana wersja, która jest krótsza o 14 pełnych bajtów (łącznie 107 bajtów):
function ordinal($i) {
return $i.(($j=abs($i)%100)>10&&$j<14?'th':@['th','st','nd','rd'][$j%10]?:'th');
}
Lub tak krótko, jak to możliwe, będąc o 25 bajtów krótszym (łącznie 96 bajtów):
function o($i){return $i.(($j=abs($i)%100)>10&&$j<14?'th':@['th','st','nd','rd'][$j%10]?:'th');}
Dzięki tej ostatniej funkcji po prostu wywołaj, o(121);
a zrobi dokładnie to samo, co inne funkcje, które wymieniłem.
Aktualizacja kodu nr 2 :
Ben i ja pracowaliśmy razem i zmniejszyliśmy to o 38 bajtów (łącznie 83 bajty):
function o($i){return$i.@(($j=abs($i)%100)>10&&$j<14?th:[th,st,nd,rd][$j%10]?:th);}
Nie sądzimy, że może to być krótsze niż to! Chcąc jednak udowodnić, że się mylisz. :)
Mam nadzieję, że wszystkim się spodoba.
abs()
z modułem%
abs();
usuwa znak minus, którego potrzebowałem.
Jeszcze krótsza wersja dla dat w miesiącu (do 31) zamiast używania mktime () i niewymagająca pecl intl:
function ordinal($n) {
return (new DateTime('Jan '.$n))->format('jS');
}
lub proceduralnie:
echo date_format(date_create('Jan '.$n), 'jS');
Działa to oczywiście, ponieważ domyślny miesiąc, który wybrałem (styczeń), ma 31 dni.
Co ciekawe, jeśli spróbujesz go z lutym (lub kolejnym miesiącem bez 31 dni), uruchomi się ponownie przed końcem:
...clip...
31st
1st
2nd
3rd
więc możesz liczyć do dni tego miesiąca ze specyfikatorem daty t
w pętli: liczba dni w miesiącu.
Znalazłem odpowiedź w 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';
}
?>
Oto kolejna bardzo krótka wersja korzystająca z funkcji daty. Działa dla dowolnej liczby (nie jest ograniczona liczbą dni miesiąca) i bierze pod uwagę, że * 11 * 12 * 13 nie ma formatu * 1 * 2 * 3.
function getOrdinal($n)
{
return $n . date_format(date_create('Jan ' . ($n % 100 < 20 ? $n % 20 : $n % 10)), 'S');
}
Podoba mi się ten mały fragment
<?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';
}
?>