Afficher les nombres avec le suffixe ordinal en PHP

149

Je souhaite afficher les nombres comme suit

  • 1 comme 1er,
  • 2 comme 2ème,
  • ...,
  • 150 comme 150e.

Comment trouver le suffixe ordinal correct (st, nd, rd ou th) pour chaque nombre de mon code?

Arche
la source
2
Voir ma réponse ici. stackoverflow.com/questions/69262/ ... Cette question était pour .NET, mais j'ai répondu avec une solution PHP, donc cela devrait vous aider.
nickf
La seule façon dont je peux penser à faire cela est d'avoir une instruction if qui monte pour chaque nombre que vous pourriez avoir, IE, if (1) puis "st" elseif (2) puis "nd" etc etc if (23000) then " nd ". C'est un problème si vous avez de gros nombres mais que vous pouvez écrire un programme pour écrire le code pour vous, il pourrait boucler tous les nombres en imprimant les si pour que vous puissiez les copier + coller dans votre code.
Tom Gullen
2
@Tom, une table de recherche pourrait être meilleure, il suffit de l'initialiser avec les 23000 valeurs et d'obtenir la valeur à l'index n, où n est le nombre dont vous voulez l'ordinal.
John Boker
2
Le colonel Shrapnel. vous pouvez brillant mais pas tout. de toute façon merci de votre intérêt pour ma question
ArK
@John, idée très très intelligente, il serait très rapide d'accès et chaque index représente le numéro que vous recherchez.
Tom Gullen

Réponses:

283

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

$numberest le numéro que vous souhaitez écrire. Fonctionne avec n'importe quel nombre naturel.

En tant que fonction:

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);
Iacopo
la source
Bien qu'un peu difficile à comprendre au début, je pense maintenant que cela représente le mieux le fonctionnement du système de suffixes ordinaux pour l'anglais.
erisco
6
J'aime ta solution. De plus, si vous préférez ne pas générer 0e, modifiez la dernière ligne pour qu'elle soit$abbreviation = ($number)? $number. $ends[$number % 10] : $number;
Gavin Jackson
1
@GavinJackson votre ajout à cette excellente solution m'a vraiment aidé (+1). Pouvez-vous m'expliquer ce qui se passe dans le calcul? Je veux comprendre. À votre santé! EDIT: Trouvé une réponse: opérateur conditionnel
Andrew Fox
Désolé, j'ai dû briser les 111 voix contre 112: D En a fait une fonction dans Delphi avec une application de démonstration: pastebin.com/wvmz1CHY
Jerry Dodge
1
@HafezDivandari - êtes-vous sûr? Juste testé avec 7.1.19 et semble fonctionner correctement
Iacopo
142

PHP a des fonctionnalités intégrées pour cela . Il gère même l'internationalisation!

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

Notez que cette fonctionnalité n'est disponible que dans PHP 5.3.0 et versions ultérieures.

Jeremy Kauffman
la source
15
Notez que cela nécessite également PECL intl> = 1.0.0
rymo
4
Savez-vous s'il est possible d'obtenir le nombre ordinal sous forme de mot? c'est-à-dire premier, deuxième, troisième, etc. au lieu de 1er, 2e, 3e ...
its_me
@jeremy Quand j'ai essayé d'utiliser NumberFormatter, cela lève toujours une erreur NumberFomatter file not found. Comment avez-vous contourné cela?
jhnferraris
1
@Jhn vous devez installer l'extensionapt-get install php5-intl
Aley
@Aley je vois. Yii a un formateur intégré que nous utilisons actuellement. heh
jhnferraris
20

Cela peut être accompli en une seule ligne en exploitant des fonctionnalités similaires dans les fonctions de date / heure intégrées de PHP. Je soumets humblement:

Solution:

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

Explication détaillée:

La date()fonction intégrée a une logique de suffixe pour gérer les calculs du nième jour du mois. Le suffixe est renvoyé lorsqu'il Sest indiqué dans la chaîne de format:

date( 'S' , ? );

Depuis date()nécessite un horodatage (pour ?ci - dessus), nous allons passer notre entier en $ntant que dayparamètre mktime()et l' utilisation des valeurs fictives de 1la hour, minute, secondet month:

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

Cela échoue en fait gracieusement sur les valeurs hors plage pour un jour du mois (c'est-à-dire $n > 31), mais nous pouvons ajouter une logique en ligne simple pour plafonner $nà 29:

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

La seule valeur positive( Mai 2017 ) cela échoue $n == 0, mais c'est facilement résolu en ajoutant 10 dans ce cas particulier:

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

Mise à jour, mai 2017

Comme observé par @donatJ, ce qui précède échoue au-dessus de 100 (par exemple "111st"), car les >=20vérifications retournent toujours vrai. Pour les réinitialiser tous les siècles, nous ajoutons un filtre à la comparaison:

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

Emballez-le simplement dans une fonction pour plus de commodité et c'est parti!

Andrew Kozak
la source
14

Voici un one-liner:

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

Probablement la solution la plus courte. Peut bien sûr être enveloppé par une fonction:

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

Cordialement, Paul

EDIT1: Correction du code pour 11 à 13.

EDIT2: Correction du code pour 111, 211, ...

EDIT3: Maintenant, cela fonctionne correctement aussi pour les multiples de 10.

Paul
la source
J'aime cette approche, mais hélas, ça ne fonctionne pas: - (30e sort comme 30e. 40e sort comme 40e. Etc.
Flukey
1
Ouais désolé. Quand j'ai lu la question, j'ai pensé, hé cela devrait être possible par une seule ligne de code. Et je l'ai juste tapé. Comme vous le voyez d'après mes modifications, je m'améliore. Après la troisième édition, je pense que c'est tout à fait terminé. Au moins tous les nombres de 1 à 150 s'impriment bien sur mon écran.
Paul
Ça a l'air bien jusqu'à 500! (ne l'ai pas testé plus loin que cela). Bon travail! :-)
Flukey
13

depuis 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;
}
?> 
John Boker
la source
9

La réponse simple et facile sera:

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

//OUTPUT - rd
Cheval Blanc
la source
Ne dit rien sur les dates dans la question tho. J'ai quand même voté pour - c'est une solution rapide et simple quand vous savez que la plage de numéros va être <32
cronoklee
8

J'ai écrit ceci pour PHP4. Cela fonctionne bien et c'est assez économique.

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';  
}
iletras
la source
Vishal Kumar, pourriez-vous développer / expliquer / expliquer cela un peu plus? Tks!
iletras
4

il vous suffit d'appliquer une fonction donnée.

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';
}
Chintan Thummar
la source
3

De manière générique, vous pouvez l'utiliser et appeler 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';
}
?>
Uzair Bin Nisar
la source
2

J'ai créé une fonction qui ne repose pas sur la date();fonction de PHP car ce n'est pas nécessaire, mais je l'ai également rendue aussi compacte et aussi courte que je pense que c'est actuellement possible.

Le code : (121 octets au total)

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

Code plus compact ci-dessous.

Cela fonctionne comme suit :

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.

Choses à savoir sur cette fonction :

  • Il traite les entiers négatifs de la même manière que les entiers positifs et conserve le signe.
  • Il renvoie 11e, 12e, 13e, 811e, 812e, 813e, etc. pour les- quinze nombres comme prévu.
  • Il ne vérifie pas les décimales, mais les laisser en place (utilisation floor($i), round($i)ou ceil($i)au début de l'instruction return final).
  • Vous pouvez également ajouter format_number($i) au début de l'instruction de retour finale pour obtenir un entier séparé par des virgules (si vous affichez des milliers, des millions, etc.).
  • Vous pouvez simplement supprimer le $idepuis le début de l'instruction return si vous souhaitez uniquement renvoyer le suffixe ordinal sans ce que vous avez entré.

Cette fonction fonctionne à partir de PHP 5.2 publié en novembre 2006 uniquement à cause de la syntaxe des tableaux courts. Si vous avez une version antérieure à celle-ci, veuillez mettre à jour car vous êtes presque dix ans à jour! A défaut, remplacez simplement le en ligne ['st', 'nd', 'rd']par une variable temporaire contenantarray('st', 'nd', 'rd'); .

La même fonction (sans retourner l'entrée), mais une vue éclatée de ma fonction courte pour une meilleure compréhension:

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
}

Mise à jour du code :

Voici une version modifiée qui est plus courte de 14 octets entiers (107 octets au total):

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

Ou pour aussi court que possible étant 25 octets plus court (96 octets au total):

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

Avec cette dernière fonction, appelez simplement o(121);et cela fera exactement la même chose que les autres fonctions que j'ai énumérées.

Mise à jour du code n ° 2 :

Ben et moi avons travaillé ensemble et l'avons réduit de 38 octets (83 octets au total):

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

Nous ne pensons pas que cela puisse être plus court que cela! Prêt à se tromper, cependant. :)

J'espère que vous apprécierez tous.

nxasdf
la source
vous n'avez pas besoin d'utiliser abs()avec module%
99 Problèmes - La syntaxe n'est pas un
Le fait de se fier uniquement à modulo laissera toujours le signe négatif en place. abs();supprime le signe négatif dont j'avais besoin.
nxasdf
1

Une version encore plus courte pour les dates du mois (jusqu'à 31) au lieu d'utiliser mktime () et ne nécessitant pas pecl intl:

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

ou procédural:

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

Cela fonctionne bien sûr car le mois par défaut que j'ai choisi (janvier) compte 31 jours.

Chose intéressante si vous l'essayez avec février (ou un autre mois sans 31 jours), il redémarre avant la fin:

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

afin que vous puissiez compter jusqu'aux jours de ce mois avec le spécificateur de date tdans votre boucle: nombre de jours dans le mois.

Dan Dart
la source
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;
  }
xyz
la source
0

J'ai trouvé une réponse dans 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';
}
?>
mysticmo
la source
0

Voici une autre version très courte utilisant les fonctions de date. Cela fonctionne pour n'importe quel nombre (non limité par les jours du mois) et prend en compte que * 11 * 12 * 13 ne suit pas le format * 1er * 2ème * 3ème.

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

J'adore ce petit extrait

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

?>

ICI

Niksmac
la source
1
Je ne suis pas tout à fait sûr de ce que cette réponse offre en plus de la réponse de ChintanThummar. Eh bien, cela laisse entendre que ChintanThummar a commis une violation du droit d'auteur, à moins qu'il n'écrive le code à votre source ...
Andreas Rejbrand