Adicione o sufixo st, nd, rd e th (ordinal) a um número

150

Gostaria de gerar dinamicamente uma sequência de texto com base nos dias atuais. Por exemplo, se for o dia 1, gostaria que meu código gere = "É a <dinâmica> 1 * <cadeia dinâmica> st </ cadeia dinâmica> * </dynamic>".

Há 12 dias no total, então eu fiz o seguinte:

  1. Eu configurei um loop for que percorre os 12 dias.

  2. No meu html, dei ao meu elemento um ID exclusivo com o qual segmentá-lo, veja abaixo:

    <h1 id="dynamicTitle" class="CustomFont leftHeading shadow">On The <span></span> <em>of rest of generic text</em></h1>
  3. Então, dentro do meu loop for, tenho o seguinte código:

    $("#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"
    }

ATUALIZAR

Este é o loop for inteiro, conforme solicitado:

$(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
fonte
1
Se o seu código-fonte for curto o suficiente, você se importaria de postar tudo e também dizer exatamente o que está errado ou o que está confundindo você?
RonaldBarzell
O que seu código faz / não faz atualmente? Você não declarou claramente o que está acontecendo de errado.
Pointy
Eu estou supondo que o código mostrado é o conteúdo de um ifbloco que é ainda contido pelo loop? Mostrar mais código ....
MrCode 29/11
@ MrCode - Sim, você está correto. Atualizei a postagem para incluir todo o loop for. Espero que isso esclareça tudo!
Antonio Vasilev
limpo e funciona bem.
Dan Jay

Respostas:

345

As regras são as seguintes:

  • st é usado com números que terminam em 1 (por exemplo, 1º, pronunciado primeiro)
  • nd é usado com números que terminam em 2 (por exemplo, 92º, pronunciado noventa segundos)
  • rd é usado com números que terminam em 3 (por exemplo, 33º, pronunciado trigésimo terceiro)
  • Como exceção às regras acima, todos os números "adolescentes" que terminam com 11, 12 ou 13 usam -th (por exemplo, 11º, pronunciado décimo primeiro, 112º, pronunciado cento e décimo segundo)
  • th é usado para todos os outros números (por exemplo, 9º, nono pronunciado).

O seguinte código JavaScript (reescrito em jun '14) realiza isso:

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

Exemplo de saída para números entre 0 e 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
fonte
1
Também funcionou muito bem para o meu: dateString = monthNames [newValue.getUTCMonth ()] + "" + numberSuffix (newValue.getUTCDate ()) + "," + newValue.getUTCFullYear ();
Michael J. Calkins
9
Isso não trata as exceções para os três números "adolescentes" corretamente. Por exemplo, os números 111, 112e 113deve resultar em "111th", "112th"e, "113th"respectivamente, não o "111st", "112nd", e "113rd"produzido pela função, tal como actualmente codificada.
martineau
3
Essa resposta parece ter evoluído perfeitamente. Obrigado a todos os colaboradores.
Lonnie Best
7
I sqeezed-lo como um lambda ES6 sem motivo real: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 engraçado o suficiente, depois de ~ π / 2 anos depois, eu ainda posso lê-lo.
Camilo Martin
210

No 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
fonte
22
Adicionar explicação pode torná-la uma resposta melhor!
Pugazh
5
@Pugazh A. encontre s [v% 10] se> = 20 (20 ... 99th), B. se não for encontrado, tente s [v] (0th..3rd), C. se ainda não for encontrado, use s [0] (4th..19th)
Sheepy
4
por que o duplo entra no nome da função?
Gisheri
46

Abordagem mínima de uma linha para sufixos ordinais

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

(isto é para números inteiros positivos, veja abaixo outras variações)

Explicação

Comece com uma matriz com os sufixos ["st", "nd", "rd"]. Queremos mapear números inteiros terminando em 1, 2, 3 (mas não terminando em 11, 12, 13) para os índices 0, 1, 2.

Outros números inteiros (incluindo aqueles que terminam em 11, 12, 13) podem ser mapeados para qualquer outra coisa - os índices não encontrados na matriz serão avaliados como undefined . Isso é falso em javascript e com o uso de logic ou ( || "th") a expressão retornará"th" para esses números inteiros, exatamente o que queremos.

A expressão ((n + 90) % 100 - 10) % 10 - 1 faz o mapeamento. Dividindo:

  • (n + 90) % 100: Esta expressão leva o número inteiro de entrada - 10 mod 100, mapeando 10 a 0, ... 99 a 89, 0 a 90, ..., 9 a 99. Agora, os números inteiros que terminam em 11, 12, 13 estão no mais baixo end (mapeado para 1, 2, 3).
  • - 10: Agora 10 é mapeado para −10, 19 para -1, 99 para 79, 0 para 80, ... 9 a 89. Os números inteiros que terminam em 11, 12, 13 são mapeados para números inteiros negativos (−9, −8, -7).
  • % 10: Agora todos os números inteiros que terminam em 1, 2 ou 3 são mapeados para 1, 2, 3. Todos os outros números inteiros são mapeados para outra coisa (11, 12, 13 ainda são mapeados para -9, -8, -7).
  • - 1: Subtrair um fornece o mapeamento final de 1, 2, 3 a 0, 1, 2.

Verificando se funciona

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>

Variações

Permitindo números inteiros negativos:

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

Na sintaxe da seta gorda ES6 (função anônima):

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

Atualizar

Uma alternativa ainda mais curta para números inteiros positivos é a expressão

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

Veja este post para explicação.

Atualização 2

[,'st','nd','rd'][n/10%10^1&&n%10]||'th'
Tomas Langkaas
fonte
3
elegante. meu favorito.
cara Mograbi
10

Intl.PluralRules, o método padrão .

Gostaria apenas de deixar aqui a maneira canônica de fazer isso aqui, pois ninguém parece saber disso.

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

Константин Ван
fonte
1
Esta é a única boa solução geral, pois é a única resposta aqui que lida com números negativos.
RobG 5/04
7

Você só tem 12 dias? Eu ficaria tentado a torná-lo apenas uma matriz de pesquisa simples:

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

então

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

ou

var i = 8;
var day = i + suffixes[i]; // result: '8th'
Jamiec
fonte
Obrigado, isso resolveu meu problema. Como não consegui obter o sufixo correspondente ao dia, preenchi a matriz com os dois números e o sufixo que funciona perfeitamente. Eu simplesmente o chamei assim:$("#dynamicTitle span").html(suffix[i-1]);
Antonio Vasilev
7

Dividindo o número em uma matriz e revertendo, podemos verificar facilmente os últimos 2 dígitos do número usando array[0]earray[1] .

Se um número está na adolescência, array[1] = 1é necessário "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";
}
usuario
fonte
Isto é perfeito. Obrigado!
18713 Jason
Você tem que excluir 11, 12, 13
psx 15/01
2
@psx É para isso que serve a linha 5.
nick
4
function getSuffix(n) {return n < 11 || n > 13 ? ['st', 'nd', 'rd', 'th'][Math.min((n - 1) % 10, 3)] : 'th'}
Johnny
fonte
Pouco oneliner agradável, apenas um pouco difícil de entender
bryc
Falha onde n == 0 devido à n - 1peça (retorna indefinido). Também falha para números maiores que 110, por exemplo, getSuffix(111)retorna "st". Ele resolve o problema do OP, onde os números são de 1 a 12, mas não é uma solução geral. :-(
RobG 5/04
2

Eu escrevi esta função para resolver este problema:

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

Com isso, você pode colocar .addSuffix()qualquer número e isso resultará no que você deseja. Por exemplo:

var number=1234;
console.log(number.addSuffix());
// console will show: 1234th
Jimmery
fonte
Eu acho que numberneste corda var lastDigits=n.substring(number.length-2);deve ser alterado parathis
Slava Abakumov
deveria ser em nvez de this, mas obrigado por apontar esse bug! :)
Jimmery
2

Uma versão alternativa da função ordinal pode ser a seguinte:

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

As variáveis ​​são nomeadas de maneira mais explícita, usam a convenção de camelo e podem ser mais rápidas.

Daniel Harvey
fonte
No entanto, isso não funcionará para bases de código localizadas.
Daniel Harvey
1

Eu escrevi essa função simples outro dia. Embora para uma data você não precise de números maiores, isso também atenderá a valores mais altos (1013, 36021, 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
fonte
1

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

Veja a versão anotada em https://gist.github.com/furf/986113#file-annotated-js

Curto, doce e eficiente, assim como as funções de utilidade. Funciona com qualquer número inteiro / float assinado / não assinado. (Mesmo que eu não possa imaginar a necessidade de ordinalizar carros alegóricos)

hndcrftd
fonte
0

Aqui está outra opção.

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

Notou a exceção para os adolescentes? Os adolescentes são tão desajeitados!

Edit: Esqueceu 11 e 12

Bullyen
fonte
0

Eu queria fornecer uma resposta funcional para esta pergunta para complementar a resposta existente:

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)

Como criamos uma matriz de valores especiais, o importante é lembrar que as matrizes têm um índice baseado em zero, então ordinalSuffix [0] é igual a 'st'.

Nossa função numberToOrdinal verifica se o número termina em um número adolescente; nesse caso, acrescente o número com 'th', pois todos os números ordinais são 'th'. No caso de o número não ser adolescente, passamos o número para addSuffix, que adiciona o número ao ordinal, que é determinado por se o número menos 1 (porque estamos usando um índice baseado em zero), o mod 10 tem um restante de 2 ou menos é retirado da matriz, caso contrário, é 'th'.

saída de amostra:

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
fonte
0

Antigo que fiz para minhas coisas ...

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
fonte
Adicione alguma descrição sobre o código acima. Ajudaria muito mais do que um pedaço de código.
perfil completo de Mathews Sunny
0

Recomendamos vivamente a excelente biblioteca date-fns . Rápido, modular, imutável, funciona com datas padrão.

import * as DateFns from 'date-fns';

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

Consulte a documentação do date-fns: https://date-fns.org/v2.0.0-alpha.9/docs/format

Freewalker
fonte
0

Eu escrevi essa função para números mais altos e todos os casos de teste

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')
    }
}
Amaechi chuks
fonte
0

Aqui está uma abordagem um pouco diferente (não acho que as outras respostas façam isso). Não tenho certeza se eu amo ou odeio, mas funciona!

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

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

Isto é para forros e amantes de 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

Outra opção para + be number seria:

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

Também para se livrar do prefixo ordinal, use estes:

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

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

sinta-se livre para modificar para se adequar às suas necessidades

Pedro JR
fonte
0

Você também pode usar a scales::ordinal()função É rápido e simples de usar.

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

Eu recomendo isso fortemente, é super fácil e direto de ler. Espero que ajude?

  • Evita o uso de número inteiro negativo, ou seja, número menor que 1 e retorna falso
  • Retorna 0 se a entrada for 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));

RESULTADO

false
0
11th
15th
21st
32nd
43rd
70th
111th
300th
101st
um apluss
fonte
-7

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

Você pode usar

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

para posicionar o sufixo

Vishnu Vikraman
fonte
4
Este não é o que o OP estava pedindo
TetraDev