Ajouter le suffixe st, nd, rd et th (ordinal) à un nombre

150

Je souhaite générer dynamiquement une chaîne de texte basée sur un jour en cours. Ainsi, par exemple, si c'est le jour 1, je voudrais que mon code génère = "C'est le <dynamic> 1 * <dynamic string> st </ dynamic string> * </dynamic>".

Il y a 12 jours au total, j'ai donc fait ce qui suit:

  1. J'ai mis en place une boucle for qui parcourt les 12 jours.

  2. Dans mon html, j'ai donné à mon élément un identifiant unique avec lequel le cibler, voir ci-dessous:

    <h1 id="dynamicTitle" class="CustomFont leftHeading shadow">On The <span></span> <em>of rest of generic text</em></h1>
  3. Ensuite, dans ma boucle for, j'ai le code suivant:

    $("#dynamicTitle span").html(i);
    var day = i;
    if (day == 1) {
        day = i + "st";
    } else if (day == 2) {
        day = i + "nd"
    } else if (day == 3) {
        day = i + "rd"
    }

METTRE À JOUR

C'est la boucle for entière comme demandé:

$(document).ready(function () {
    for (i = 1; i <= 12; i++) {
        var classy = "";
        if (daysTilDate(i + 19) > 0) {
            classy = "future";
            $("#Day" + i).addClass(classy);
            $("#mainHeading").html("");
            $("#title").html("");
            $("#description").html("");
        } else if (daysTilDate(i + 19) < 0) {
            classy = "past";
            $("#Day" + i).addClass(classy);
            $("#title").html("");
            $("#description").html("");
            $("#mainHeading").html("");
            $(".cta").css('display', 'none');
            $("#Day" + i + " .prizeLink").attr("href", "" + i + ".html");
        } else {
            classy = "current";
            $("#Day" + i).addClass(classy);
            $("#title").html(headings[i - 1]);
            $("#description").html(descriptions[i - 1]);
            $(".cta").css('display', 'block');
            $("#dynamicImage").attr("src", ".." + i + ".jpg");
            $("#mainHeading").html("");
            $(".claimPrize").attr("href", "" + i + ".html");
            $("#dynamicTitle span").html(i);
            var day = i;
            if (day == 1) {
                day = i + "st";
            } else if (day == 2) {
                day = i + "nd"
            } else if (day == 3) {
                day = i + "rd"
            } else if (day) {
            }
        }
    }
Antonio Vasilev
la source
1
Si votre code source est suffisamment court, cela vous dérangerait-il de publier le texte complet et de dire exactement ce qui ne va pas ou ce qui vous déroute?
RonaldBarzell
Qu'est-ce que votre code fait / ne fait pas actuellement? Vous n'avez pas clairement indiqué ce qui ne va pas.
Pointy
Je suppose que le code affiché est le contenu d'un ifbloc qui est en outre contenu par la boucle? Afficher plus de code ....
MrCode
@MrCode - Oui, vous avez raison. J'ai mis à jour le message pour inclure l'intégralité de la boucle for. J'espère que cela clarifie les choses!
Antonio Vasilev
soigné et ça marche bien.
Dan Jay

Réponses:

345

Les règles sont les suivantes:

  • st est utilisé avec les nombres se terminant par 1 (par exemple, 1er, prononcé en premier)
  • nd est utilisé avec les nombres se terminant par 2 (par exemple, 92e, prononcé quatre-vingt-dix secondes)
  • rd est utilisé avec les nombres se terminant par 3 (par exemple 33e, prononcé trente-troisième)
  • En tant qu'exception aux règles ci-dessus, tous les nombres "adolescents" se terminant par 11, 12 ou 13 utilisent -th (par exemple, 11e, prononcé onzième, 112e, prononcé cent [et] douzième)
  • th est utilisé pour tous les autres nombres (par exemple 9e, prononcé neuvième).

Le code JavaScript suivant (réécrit en juin 14) accomplit ceci:

function ordinal_suffix_of(i) {
    var j = i % 10,
        k = i % 100;
    if (j == 1 && k != 11) {
        return i + "st";
    }
    if (j == 2 && k != 12) {
        return i + "nd";
    }
    if (j == 3 && k != 13) {
        return i + "rd";
    }
    return i + "th";
}

Exemple de sortie pour les nombres compris entre 0 et 115:

  0  0th
  1  1st
  2  2nd
  3  3rd
  4  4th
  5  5th
  6  6th
  7  7th
  8  8th
  9  9th
 10  10th
 11  11th
 12  12th
 13  13th
 14  14th
 15  15th
 16  16th
 17  17th
 18  18th
 19  19th
 20  20th
 21  21st
 22  22nd
 23  23rd
 24  24th
 25  25th
 26  26th
 27  27th
 28  28th
 29  29th
 30  30th
 31  31st
 32  32nd
 33  33rd
 34  34th
 35  35th
 36  36th
 37  37th
 38  38th
 39  39th
 40  40th
 41  41st
 42  42nd
 43  43rd
 44  44th
 45  45th
 46  46th
 47  47th
 48  48th
 49  49th
 50  50th
 51  51st
 52  52nd
 53  53rd
 54  54th
 55  55th
 56  56th
 57  57th
 58  58th
 59  59th
 60  60th
 61  61st
 62  62nd
 63  63rd
 64  64th
 65  65th
 66  66th
 67  67th
 68  68th
 69  69th
 70  70th
 71  71st
 72  72nd
 73  73rd
 74  74th
 75  75th
 76  76th
 77  77th
 78  78th
 79  79th
 80  80th
 81  81st
 82  82nd
 83  83rd
 84  84th
 85  85th
 86  86th
 87  87th
 88  88th
 89  89th
 90  90th
 91  91st
 92  92nd
 93  93rd
 94  94th
 95  95th
 96  96th
 97  97th
 98  98th
 99  99th
100  100th
101  101st
102  102nd
103  103rd
104  104th
105  105th
106  106th
107  107th
108  108th
109  109th
110  110th
111  111th
112  112th
113  113th
114  114th
115  115th
Salman A
la source
1
Cela a très bien fonctionné pour le mien aussi: dateString = monthNames [newValue.getUTCMonth ()] + "" + numberSuffix (newValue.getUTCDate ()) + "," + newValue.getUTCFullYear ();
Michael J. Calkins
9
Cela ne gère pas correctement les exceptions pour les trois numéros «adolescent». Par exemple , les chiffres 111, 112et 113devrait entraîner "111th", "112th"et "113th"respectivement, pas la "111st", "112nd"et "113rd"produit par la fonction telle qu'elle est actuellement codé.
martineau
3
Cette réponse semble avoir parfaitement évolué. Merci à tous les contributeurs.
Lonnie Best
7
Je l'ai choisi comme un lambda ES6 sans vraie raison:n=>n+(n%10==1&&n%100!=11?'st':n%10==2&&n%100!=12?'nd':n%10==3&&n%100!=13?'rd':'th')
Camilo Martin
1
@Anomaly assez curieusement, après ~ π / 2 ans plus tard, je peux toujours le lire.
Camilo Martin
211

de Shopify

function getNumberWithOrdinal(n) {
  var s = ["th", "st", "nd", "rd"],
      v = n % 100;
  return n + (s[(v - 20) % 10] || s[v] || s[0]);
}

[-4,-1,0,1,2,3,4,10,11,12,13,14,20,21,22,100,101,111].forEach(
  n => console.log(n + ' -> ' + getNumberWithOrdinal(n))
);

Fizer Khan
la source
22
L'ajout d'explications peut en faire une meilleure réponse!
Pugazh
5
@Pugazh A. trouver s [v% 10] si> = 20 (20e ... 99e), B. si non trouvé, essayer s [v] (0e..3e), C. si toujours pas trouvé, utiliser s [0] (4e ... 19e)
Sheepy
4
pourquoi le double entre dans le nom de la fonction?
Gisheri
46

Approche minimale sur une ligne pour les suffixes ordinaux

function nth(n){return["st","nd","rd"][((n+90)%100-10)%10-1]||"th"}

(c'est pour les entiers positifs, voir ci-dessous pour d'autres variations)

Explication

Commencez par un tableau avec les suffixes ["st", "nd", "rd"]. Nous voulons mapper les entiers se terminant par 1, 2, 3 (mais ne se terminant pas par 11, 12, 13) aux index 0, 1, 2.

D'autres entiers (y compris ceux se terminant par 11, 12, 13) peuvent être mappés à n'importe quoi d'autre - les index non trouvés dans le tableau seront évalués undefined. C'est faux en javascript et avec l'utilisation de logique ou ( || "th"), l'expression retournera "th"pour ces entiers, ce qui est exactement ce que nous voulons.

L'expression ((n + 90) % 100 - 10) % 10 - 1fait le mappage. Décomposer:

  • (n + 90) % 100: Cette expression prend l'entier d'entrée - 10 mod 100, mappant 10 à 0, ... 99 à 89, 0 à 90, ..., 9 à 99. Maintenant, les entiers se terminant par 11, 12, 13 sont au plus bas end (mappé sur 1, 2, 3).
  • - 10: Maintenant 10 est mappé à −10, 19 à −1, 99 à 79, 0 à 80, ... 9 à 89. Les entiers se terminant par 11, 12, 13 sont mappés à des entiers négatifs (−9, −8, −7).
  • % 10: Maintenant, tous les entiers se terminant par 1, 2 ou 3 sont mappés à 1, 2, 3. Tous les autres entiers sont mappés à quelque chose d'autre (11, 12, 13 sont toujours mappés à -9, -8, -7).
  • - 1: En soustrayant un, on obtient le mappage final de 1, 2, 3 à 0, 1, 2.

Vérifier que cela fonctionne

function nth(n){return["st","nd","rd"][((n+90)%100-10)%10-1]||"th"}

//test integers from 1 to 124
for(var r = [], i = 1; i < 125; i++) r.push(i + nth(i));

//output result
document.getElementById('result').innerHTML = r.join('<br>');
<div id="result"></div>

Variations

Autoriser les entiers négatifs:

function nth(n){return["st","nd","rd"][(((n<0?-n:n)+90)%100-10)%10-1]||"th"}

Dans la syntaxe de la grosse flèche ES6 (fonction anonyme):

n=>["st","nd","rd"][(((n<0?-n:n)+90)%100-10)%10-1]||"th"

Mettre à jour

Une alternative encore plus courte pour les entiers positifs est l'expression

[,'st','nd','rd'][n%100>>3^1&&n%10]||'th'

Voir cet article pour une explication.

Mise à jour 2

[,'st','nd','rd'][n/10%10^1&&n%10]||'th'
Tomas Langkaas
la source
3
élégant. mon préféré.
guy mograbi
10

Intl.PluralRules, la méthode standard .

Je voudrais simplement laisser tomber la manière canonique de faire cela ici, car personne ne semble le savoir.

const english_ordinal_rules = new Intl.PluralRules("en", {type: "ordinal"});
const suffixes = {
	one: "st",
	two: "nd",
	few: "rd",
	other: "th"
};
function ordinal(number) {
	const suffix = suffixes[english_ordinal_rules.select(number)];
	return (number + suffix);
}

const test = Array(201)
	.fill()
	.map((_, index) => index - 100)
	.map(ordinal)
	.join(" ");
console.log(test);

Константин Ван
la source
1
C'est la seule bonne solution générale car c'est la seule réponse ici qui gère les nombres négatifs.
RobG
7

Vous n'avez que 12 jours? Je serais tenté d'en faire juste un simple tableau de recherche:

var suffixes = ['','st','nd','rd','th','th','th','th','th','th','th','th','th'];

puis

var i = 2;
var day = i + suffixes[i]; // result: '2nd'

ou

var i = 8;
var day = i + suffixes[i]; // result: '8th'
Jamiec
la source
Merci, cela a résolu mon problème. Je n'ai pas pu obtenir le suffixe correspondant au jour, alors j'ai juste rempli le tableau avec, à la fois, les chiffres et le suffixe qui fonctionne parfaitement. Je l'ai alors simplement appelé comme$("#dynamicTitle span").html(suffix[i-1]);
Antonio Vasilev
7

En divisant le nombre dans un tableau et en inversant, nous pouvons facilement vérifier les 2 derniers chiffres du nombre en utilisant array[0]et array[1].

Si un nombre est dans l'adolescence, array[1] = 1il faut "th".

function getDaySuffix(num)
{
    var array = ("" + num).split("").reverse(); // E.g. 123 = array("3","2","1")

    if (array[1] != "1") { // Number is in the teens
        switch (array[0]) {
            case "1": return "st";
            case "2": return "nd";
            case "3": return "rd";
        }
    }

    return "th";
}
pseudo
la source
C'est parfait. Merci!
Jason le
Vous devez exclure 11, 12, 13
psx
2
@psx C'est à cela que sert la condition de la ligne 5.
pseudo le
4
function getSuffix(n) {return n < 11 || n > 13 ? ['st', 'nd', 'rd', 'th'][Math.min((n - 1) % 10, 3)] : 'th'}
Johnny
la source
Joli petit oneliner, juste un peu difficile à comprendre
bryc
Échoue où n == 0 en raison de la n - 1pièce (renvoie undefined). Échoue également pour les nombres supérieurs à 110, par exemple getSuffix(111)renvoie "st". Cela résout le problème du PO où les nombres vont de 1 à 12, mais ce n'est pas une solution générale. :-(
RobG
2

J'ai écrit cette fonction pour résoudre ce problème:

// this is for adding the ordinal suffix, turning 1, 2 and 3 into 1st, 2nd and 3rd
Number.prototype.addSuffix=function(){
    var n=this.toString().split('.')[0];
    var lastDigits=n.substring(n.length-2);
    //add exception just for 11, 12 and 13
    if(lastDigits==='11' || lastDigits==='12' || lastDigits==='13'){
        return this+'th';
    }
    switch(n.substring(n.length-1)){
        case '1': return this+'st';
        case '2': return this+'nd';
        case '3': return this+'rd';
        default : return this+'th';
    }
};

Avec cela, vous pouvez simplement mettre .addSuffix()n'importe quel nombre et cela donnera ce que vous voulez. Par exemple:

var number=1234;
console.log(number.addSuffix());
// console will show: 1234th
Jimmery
la source
Je pense que numbercette chaîne var lastDigits=n.substring(number.length-2);devrait être remplacée parthis
Slava Abakumov
il devrait l'être à la nplace de this, mais merci d'avoir signalé ce bug! :)
Jimmery
2

Une version alternative de la fonction ordinale pourrait être la suivante:

function toCardinal(num) {
    var ones = num % 10;
    var tens = num % 100;

    if (tens < 11 || tens > 13) {
        switch (ones) {
            case 1:
                return num + "st";
            case 2:
                return num + "nd";
            case 3:
                return num + "rd";
        }
    }

    return num + "th";
}

Les variables sont nommées plus explicitement, utilisent la convention de casse camel et peuvent être plus rapides.

Daniel Harvey
la source
Cela ne fonctionnera cependant pas pour les bases de code localisées.
Daniel Harvey
1

J'ai écrit cette fonction simple l'autre jour. Bien que pour une date, vous n'ayez pas besoin des plus grands nombres, cela prendra également en charge des valeurs plus élevées (1013e, 36021e etc ...)

var fGetSuffix = function(nPos){

    var sSuffix = "";

    switch (nPos % 10){
        case 1:
            sSuffix = (nPos % 100 === 11) ? "th" : "st";
            break;
        case 2:
            sSuffix = (nPos % 100 === 12) ? "th" : "nd";
            break;
        case 3:
            sSuffix = (nPos % 100 === 13) ? "th" : "rd";
            break;
        default:
            sSuffix = "th";
            break;
    }

    return sSuffix;
};
Sir Kettle
la source
1

function ordsfx(a){return["th","st","nd","rd"][(a=~~(a<0?-a:a)%100)>10&&a<14||(a%=10)>3?0:a]}

Voir la version annotée sur https://gist.github.com/furf/986113#file-annotated-js

Courte, douce et efficace, tout comme les fonctions utilitaires devraient l'être. Fonctionne avec n'importe quel entier / flottant signé / non signé. (Même si je ne peux pas imaginer un besoin d'ordinaliser les flotteurs)

hndcrftd
la source
0

Voici une autre option.

function getOrdinalSuffix(day) {
        
   	if(/^[2-3]?1$/.test(day)){
   		return 'st';
   	} else if(/^[2-3]?2$/.test(day)){
   		return 'nd';
   	} else if(/^[2-3]?3$/.test(day)){
   		return 'rd';
   	} else {
   		return 'th';
   	}
        
}
    
console.log(getOrdinalSuffix('1'));
console.log(getOrdinalSuffix('13'));
console.log(getOrdinalSuffix('22'));
console.log(getOrdinalSuffix('33'));

Remarquez l'exception pour les adolescents? Les adolescents sont si méchants!

Edit: j'ai oublié les 11 et 12

Bullyen
la source
0

Je voulais apporter une réponse fonctionnelle à cette question pour compléter la réponse existante:

const ordinalSuffix = ['st', 'nd', 'rd']
const addSuffix = n => n + (ordinalSuffix[(n - 1) % 10] || 'th')
const numberToOrdinal = n => `${n}`.match(/1\d$/) ? n + 'th' : addSuffix(n)

nous avons créé un tableau des valeurs spéciales, la chose importante à retenir est que les tableaux ont un index basé sur zéro donc ordinalSuffix [0] est égal à «st».

Notre fonction numberToOrdinal vérifie si le nombre se termine par un nombre d'adolescent, auquel cas ajoutez le nombre avec «th» car tous les nombres ordinaux sont «th». Dans le cas où le nombre n'est pas un adolescent, nous passons le nombre à addSuffix qui ajoute le nombre à l'ordinal qui est déterminé par si le nombre moins 1 (car nous utilisons un index basé sur zéro) mod 10 a un reste de 2 ou moins, il est pris dans le tableau, sinon c'est «th».

exemple de sortie:

numberToOrdinal(1) // 1st
numberToOrdinal(2) // 2nd
numberToOrdinal(3) // 3rd
numberToOrdinal(4) // 4th
numberToOrdinal(5) // 5th
numberToOrdinal(6) // 6th
numberToOrdinal(7) // 7th
numberToOrdinal(8) // 8th
numberToOrdinal(9) // 9th
numberToOrdinal(10) // 10th
numberToOrdinal(11) // 11th
numberToOrdinal(12) // 12th
numberToOrdinal(13) // 13th
numberToOrdinal(14) // 14th
numberToOrdinal(101) // 101st
Peter McArthur
la source
0

Ancien que j'ai fait pour mes affaires ...

function convertToOrdinal(number){
    if (number !=1){
        var numberastext = number.ToString();
        var endchar = numberastext.Substring(numberastext.Length - 1);
        if (number>9){
            var secondfromendchar = numberastext.Substring(numberastext.Length - 1);
            secondfromendchar = numberastext.Remove(numberastext.Length - 1);
        }
        var suffix = "th";
        var digit = int.Parse(endchar);
        switch (digit){
            case 3:
                if(secondfromendchar != "1"){
                    suffix = "rd";
                    break;
                }
            case 2:
                if(secondfromendchar != "1"){
                    suffix = "nd";
                    break;
                }
            case 1:
                if(secondfromendchar != "1"){
                    suffix = "st";
                    break;
                }
            default:
                suffix = "th";
                break;
         }
            return number+suffix+" ";
     } else {
            return;
     }
}
user10304
la source
Ajoutez une description du code ci-dessus. Cela aiderait beaucoup plus qu'un morceau de code.
Mathews Sunny
0

Je recommande vivement l'excellente bibliothèque date-fns . Rapide, modulaire, immuable, fonctionne avec des dates standard.

import * as DateFns from 'date-fns';

const ordinalInt = DateFns.format(someInt, 'do');

Voir la documentation date-fns: https://date-fns.org/v2.0.0-alpha.9/docs/format

Freewalker
la source
0

J'ai écrit cette fonction pour des nombres plus élevés et tous les cas de test

function numberToOrdinal(num) {
    if (num === 0) {
        return '0'
    };
    let i = num.toString(), j = i.slice(i.length - 2), k = i.slice(i.length - 1);
    if (j >= 10 && j <= 20) {
        return (i + 'th')
    } else if (j > 20 && j < 100) {
        if (k == 1) {
            return (i + 'st')
        } else if (k == 2) {
            return (i + 'nd')
        } else if (k == 3) {
            return (i + 'rd')
        } else {
            return (i + 'th')
        }
    } else if (j == 1) {
        return (i + 'st')
    } else if (j == 2) {
        return (i + 'nd')
    } else if (j == 3) {
        return (i + 'rd')
    } else {
        return (i + 'th')
    }
}
Chuks Amaechi
la source
0

Voici une approche légèrement différente (je ne pense pas que les autres réponses le font). Je ne sais pas si je l'aime ou le déteste, mais ça marche!

export function addDaySuffix(day: number) { 
  const suffixes =
      '  stndrdthththththththththththththththththstndrdthththththththst';
    const startIndex = day * 2;

    return `${day}${suffixes.substring(startIndex, startIndex + 2)}`;
  }
Dave Cooper
la source
0

Ceci est pour un liners et les amateurs d'es6

let i= new Date().getDate 

// I can be any number, for future sake we'll use 9

const j = I % 10;
const k = I % 100;

i = `${i}${j === 1 &&  k !== 11 ? 'st' : j === 2 && k !== 12 ? 'nd' : j === 3 && k !== 13 ? 'rd' : 'th'}`}

console.log(i) //9th

Une autre option pour + serait le nombre serait:

console.log(["st","nd","rd"][((i+90)%100-10)%10-1]||"th"]

Aussi pour se débarrasser du préfixe ordinal, utilisez simplement ceux-ci:

console.log(i.parseInt("8th"))

console.log(i.parseFloat("8th"))

n'hésitez pas à modifier selon vos besoins

Pedro JR
la source
0

Vous pouvez également utiliser la scales::ordinal()fonction. C'est simple et rapide à utiliser.

scales::ordinal(1:12)
## [1] "1st"  "2nd"  "3rd"  "4th"  "5th"  "6th"  "7th"  "8th"  "9th"  "10th" "11th" "12th"
phargart
la source
-1

Je recommande fortement cela, c'est super facile et simple à lire. J'espère que ça aide?

  • Il évite l'utilisation d'un entier négatif, c'est-à-dire un nombre inférieur à 1 et renvoie faux
  • Il renvoie 0 si l'entrée est 0
function numberToOrdinal(n) {

  let result;

  if(n < 0){
    return false;
  }else if(n === 0){
    result = "0";
  }else if(n > 0){

    let nToString = n.toString();
    let lastStringIndex = nToString.length-1;
    let lastStringElement = nToString[lastStringIndex];

    if( lastStringElement == "1" && n % 100 !== 11 ){
      result = nToString + "st";
    }else if( lastStringElement == "2" && n % 100 !== 12 ){
      result = nToString + "nd";
    }else if( lastStringElement == "3" && n % 100 !== 13 ){
      result = nToString + "rd";
    }else{
      result = nToString + "th";
    }

  }

  return result;
}

console.log(numberToOrdinal(-111));
console.log(numberToOrdinal(0));
console.log(numberToOrdinal(11));
console.log(numberToOrdinal(15));
console.log(numberToOrdinal(21));
console.log(numberToOrdinal(32));
console.log(numberToOrdinal(43));
console.log(numberToOrdinal(70));
console.log(numberToOrdinal(111));
console.log(numberToOrdinal(300));
console.log(numberToOrdinal(101));

PRODUCTION

false
0
11th
15th
21st
32nd
43rd
70th
111th
300th
101st
an-apluss
la source
-7

<p>31<sup>st</sup> March 2015</p>

Vous pouvez utiliser

1<sup>st</sup> 2<sup>nd</sup> 3<sup>rd</sup> 4<sup>th</sup>

pour positionner le suffixe

Vishnu Vikraman
la source
4
Ce n'est pas ce que le PO demandait
TetraDev