Zeigen Sie Zahlen mit Ordnungssuffix in PHP an


148

Ich möchte Zahlen wie folgt anzeigen

  • 1 als 1.,
  • 2 als 2.,
  • ...,
  • 150 als 150 ..

Wie finde ich das richtige Ordnungssuffix (st, nd, rd oder th) für jede Zahl in meinem Code?


2
Siehe meine Antwort hier. stackoverflow.com/questions/69262/… Diese Frage war für .NET, aber ich habe sie mit einer PHP-Lösung beantwortet, daher sollte sie Ihnen helfen.
Nickf

Der einzige Weg, wie ich mir das vorstellen kann, ist eine if-Anweisung für jede mögliche Zahl, IE, if (1) dann "st" elseif (2) dann "nd" etc etc if (23000) then " nd ". Es ist ein Problem, wenn Sie große Zahlen haben, aber Sie könnten ein Programm schreiben, um den Code für Sie zu schreiben. Es könnte alle Zahlen durchlaufen, die das Wenn drucken, damit Sie es kopieren und in Ihren Code einfügen können.
Tom Gullen

2
@ Tom, eine Nachschlagetabelle ist möglicherweise besser. Initialisieren Sie sie einfach mit den 23000-Werten und erhalten Sie den Wert am Index n, wobei n die Zahl ist, für die Sie die Ordnungszahl wünschen.
John Boker

2
Col. Shrapnel. Sie können brillant, aber nicht alle. Auf jeden Fall danke für das Interesse an meiner Frage
ArK

@ John, sehr, sehr clevere Idee, es wäre sehr schnell zugänglich, und jeder Index repräsentiert die Nummer, nach der Sie suchen.
Tom Gullen

Antworten:


282

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

Wo $numberist die Nummer, die Sie schreiben möchten? Funktioniert mit jeder natürlichen Zahl.

Als eine Funktion:

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

Obwohl es anfangs etwas schwer zu verstehen ist, denke ich jetzt, dass es am besten darstellt, wie das Ordnungssuffixsystem für Englisch funktioniert.
Erisco

5
Ich mag deine Lösung. Wenn Sie es vorziehen, keine 0. zu generieren, ändern Sie außerdem die letzte Zeile$abbreviation = ($number)? $number. $ends[$number % 10] : $number;
Gavin Jackson

1
@GavinJackson Ihre Ergänzung zu dieser hervorragenden Lösung hat mir wirklich geholfen (+1). Könnten Sie mir bitte erklären, was in der Berechnung vor sich geht? Ich will verstehen. Prost! EDIT: Gefunden eine Antwort: Bedingter Operator
Andrew Fox

Sorry, musste die 111 Stimmen zu 112 brechen: D machte es eine Funktion in Delphi zusammen mit einer Demo-App: pastebin.com/wvmz1CHY
Jerry Dodge

1
@ HafezDivandari - bist du sicher? Gerade mit 7.1.19 getestet und scheint gut zu funktionieren
Iacopo

141

PHP verfügt hierfür über integrierte Funktionen . Es kümmert sich sogar um die Internationalisierung!

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

Beachten Sie, dass diese Funktionalität nur in PHP 5.3.0 und höher verfügbar ist.


15
Beachten Sie, dass dies auch PECL intl> = 1.0.0
rymo

4
Wissen Sie, ob es möglich ist, die Ordnungszahl in Wortform zu erhalten? dh erste, zweite, dritte usw. statt 1., 2., 3. ...
its_me

@jeremy Wenn ich versucht habe, NumberFormatter zu verwenden, wird immer ein Fehler ausgegeben, der NumberFomatter file not found. Wie haben Sie das umgangen?
Jhnferraris

1
@Jhn müssen Sie die Erweiterung installierenapt-get install php5-intl
Aley

@Aley ich verstehe. Yii hat einen eingebauten Formatierer, den wir gerade verwenden. heh
jhnferraris

20

Dies kann in einer einzigen Zeile erreicht werden, indem ähnliche Funktionen in den in PHP integrierten Datums- / Uhrzeitfunktionen genutzt werden. Ich reiche demütig ein:

Lösung:

function ordinalSuffix( $n )
{
  return date('S',mktime(1,1,1,1,( (($n>=10)+($n>=20)+($n==0))*10 + $n%10) ));
}

Ausführliche Erklärung:

Die integrierte date()Funktion verfügt über eine Suffix-Logik für die Berechnung des n-ten Tages des Monats. Das Suffix wird zurückgegeben, wenn Ses in der Formatzeichenfolge angegeben wird:

date( 'S' , ? );

Da date()ein Zeitstempel (für erfordert ?oben), werden wir unsere ganze Zahl übergeben $nals dayParameter mktime()und die Verwendung Blindwerte 1für die hour, minute, secondund month:

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

Dies schlägt bei Werten außerhalb des Bereichs für einen Tag des Monats (dh $n > 31) ordnungsgemäß fehl, aber wir können eine einfache Inline-Logik hinzufügen, um $nbei 29 zu begrenzen :

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

Der einzig positive Wert( Mai 2017 ) Dies schlägt fehl $n == 0, aber das lässt sich leicht beheben, indem in diesem speziellen Fall 10 hinzugefügt werden:

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

Update, Mai 2017

Wie von @donatJ beobachtet, schlägt das Obige über 100 fehl (z. B. "111."), da die >=20Überprüfungen immer true zurückgeben. Um diese jedes Jahrhundert zurückzusetzen, fügen wir dem Vergleich einen Filter hinzu:

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

Wickeln Sie es einfach in eine Funktion ein und los geht's!


14

Hier ist ein Einzeiler:

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

Wahrscheinlich die kürzeste Lösung. Kann natürlich von einer Funktion umschlossen werden:

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

Grüße, Paul

EDIT1: Korrektur des Codes für 11 bis 13.

EDIT2: Korrektur des Codes für 111, 211, ...

EDIT3: Jetzt funktioniert es auch für Vielfache von 10 richtig.


Ich mag diesen Ansatz, aber leider funktioniert er nicht :-( 30. kommt als 30. heraus. 40. kommt heraus als 40. usw.
Flukey

1
Ja entschuldigung. Als ich die Frage las, dachte ich, hey, das sollte durch eine einzige Codezeile möglich sein. Und ich habe es einfach weggeschrieben. Wie Sie aus meinen Änderungen sehen, verbessere ich mich. Nach der dritten Bearbeitung denke ich jetzt, dass es ziemlich fertig ist. Zumindest alle Zahlen von 1 bis 150 werden auf meinem Bildschirm gut gedruckt.
Paul

Sieht gut aus bis zu 500! (habe es nicht weiter getestet). Gute Arbeit! :-)
Flukey

13

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

9

Einfache und einfache Antwort lautet:

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

//OUTPUT - rd

Sagt nichts über Daten in der Frage tho. Ich habe trotzdem upvoted - es ist eine schnelle und einfache Lösung, wenn Sie wissen, dass der Nummernkreis <32 sein wird
cronoklee

8

Ich habe das für PHP4 geschrieben. Es hat gut funktioniert und ist ziemlich sparsam.

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, könnten Sie das etwas näher erläutern? Tks!
Iletras

4

Sie müssen nur die angegebene Funktion anwenden.

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

Generell können Sie das verwenden und echo get_placing_string (100) aufrufen.

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

2

Ich habe eine Funktion erstellt, die sich nicht auf die PHP- date();Funktion stützt, da sie nicht erforderlich ist, sondern sie auch so kompakt und kurz gemacht hat, wie ich derzeit für möglich halte.

Der Code : (121 Bytes insgesamt)

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

Kompakterer Code unten.

Es funktioniert wie folgt :

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.

Wissenswertes zu dieser Funktion :

  • Es behandelt negative ganze Zahlen genauso wie positive ganze Zahlen und behält das Vorzeichen.
  • Es gibt erwartungsgemäß den 11., 12., 13., 811., 812., 813. usw. für die -zehn Zahlen zurück.
  • Dabei spielt es keine Dezimalzahlen überprüfen, sondern sie an ihrem Platz verläßt (Verwendung floor($i), round($i)oder ceil($i)am Anfang der letzten return - Anweisung).
  • Sie können auch format_number($i)am Anfang der endgültigen return-Anweisung hinzufügen , um eine durch Kommas getrennte Ganzzahl zu erhalten (wenn Sie Tausende, Millionen usw. anzeigen).
  • Sie können das einfach $ivom Anfang der return-Anweisung entfernen, wenn Sie nur das Ordnungssuffix ohne Ihre Eingabe zurückgeben möchten.

Diese Funktion funktioniert ab PHP 5.2, das im November 2006 veröffentlicht wurde, allein aufgrund der kurzen Array-Syntax. Wenn Sie zuvor eine Version haben, aktualisieren Sie diese bitte, da Sie fast ein Jahrzehnt veraltet sind! Andernfalls ersetzen Sie einfach die Inline ['st', 'nd', 'rd']durch eine temporäre Variable, die enthält array('st', 'nd', 'rd');.

Dieselbe Funktion (ohne Rückgabe der Eingabe), aber eine Explosionsansicht meiner Kurzfunktion zum besseren Verständnis:

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
}

Code-Aktualisierung :

Hier ist eine modifizierte Version, die 14 ganze Bytes kürzer ist (insgesamt 107 Bytes):

function ordinal($i) {
  return $i.(($j=abs($i)%100)>10&&$j<14?'th':@['th','st','nd','rd'][$j%10]?:'th');
}

Oder so kurz wie möglich, 25 Bytes kürzer (insgesamt 96 Bytes):

function o($i){return $i.(($j=abs($i)%100)>10&&$j<14?'th':@['th','st','nd','rd'][$j%10]?:'th');}

Mit dieser letzten Funktion rufen o(121);Sie einfach auf und es wird genau das gleiche tun wie die anderen Funktionen, die ich aufgelistet habe.

Code Update # 2 :

Ben und ich haben zusammengearbeitet und es um 38 Bytes (insgesamt 83 Bytes) reduziert:

function o($i){return$i.@(($j=abs($i)%100)>10&&$j<14?th:[th,st,nd,rd][$j%10]?:th);}

Wir glauben nicht, dass es kürzer werden kann! Bereit, sich jedoch als falsch zu erweisen. :) :)

Hoffe euch allen gefällt es.


Sie müssen nicht abs()mit Modul verwenden%
99 Probleme - Syntax ist nicht ein

Wenn Sie sich nur auf Modulo verlassen, bleibt das negative Vorzeichen erhalten. abs();Entfernt das negative Vorzeichen, das ich brauchte.
Nxasdf

1

Eine noch kürzere Version für Daten im Monat (bis zu 31) anstelle von mktime () und ohne pecl intl:

function ordinal($n) {
    return (new DateTime('Jan '.$n))->format('jS');
}

oder prozedural:

echo date_format(date_create('Jan '.$n), 'jS');

Dies funktioniert natürlich, da der von mir ausgewählte Standardmonat (Januar) 31 Tage hat.

Interessanterweise wird es vor dem Ende neu gestartet, wenn Sie es mit Februar (oder einem anderen Monat ohne 31 Tage) versuchen:

...clip...
31st
1st
2nd
3rd

Mit dem Datumsangaben tin Ihrer Schleife können Sie also bis zu den Tagen dieses Monats zählen : Anzahl der Tage im Monat.


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

0

In PHP.net eine Antwort gefunden

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

0

Hier ist eine weitere sehr kurze Version mit den Datumsfunktionen. Es funktioniert für jede Anzahl (nicht durch Tage des Monats beschränkt) und berücksichtigt, dass * 11th * 12th * 13th nicht dem * 1st * 2nd * 3rd-Format folgt.

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

-1

Ich mag diesen kleinen Ausschnitt

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

?>

HIER


1
Ich bin mir nicht ganz sicher, was diese Antwort zusätzlich zu ChintanThummars Antwort bietet. Nun, es deutet darauf hin, dass ChintanThummar eine Urheberrechtsverletzung begangen hat, es sei denn, er hat den Code an Ihrer Quelle geschrieben ...
Andreas Rejbrand
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.