Existe uma maneira fácil de criar ordinais em c #?

Existe uma maneira fácil em c # para criar ordinais para um número? Por exemplo:

  • 1 retorna primeiro
  • 2 retorna segundo
  • 3 retorna 3
  • … etc

Isso pode ser feito através de String.Format() ou há alguma function disponível para fazer isso?

    Esta página fornece uma listview completa de todas as regras de formatação numérica personalizadas:

    http://msdn.microsoft.com/pt-br/library/0c899ak8.aspx

    Como você pode ver, não há nada lá sobre ordinais, então não pode ser feito usando String.Format. No entanto, não é tão difícil escrever uma function para fazê-lo.

     public static string AddOrdinal(int num) { if( num < = 0 ) return num.ToString(); switch(num % 100) { case 11: case 12: case 13: return num + "th"; } switch(num % 10) { case 1: return num + "st"; case 2: return num + "nd"; case 3: return num + "rd"; default: return num + "th"; } } 

    Atualização: tecnicamente, os ordinais não existem para < = 0, então atualizei o código acima. Também removi os métodos ToString () redundantes.

    Observe também que isso não é internacionalizado. Não tenho ideia de como são os ordinais em outros idiomas.

    Lembre-se de internacionalização!

    As soluções aqui só funcionam para o inglês. As coisas ficam muito mais complexas se você precisar dar suporte a outros idiomas.

    Por exemplo, em espanhol “1st” seria escrito como “1.o”, “1.a”, “1.os” ou “1.as” dependendo se a coisa que você está contando é masculina, feminina ou plural !

    Portanto, se o seu software precisar suportar idiomas diferentes, tente evitar os ordinais.

    Minha versão da versão de Jesse das versões de Stu e samjudson 🙂

    Teste unitário incluído para mostrar que a resposta aceita está incorreta quando o número <1

      ///  /// Get the ordinal value of positive integers. ///  ///  /// Only works for english-based cultures. /// Code from: http://stackoverflow.com/questions/20156/is-there-a-quick-way-to-create-ordinals-in-c/31066#31066 /// With help: http://www.wisegeek.com/what-is-an-ordinal-number.htm ///  /// The number. /// Ordinal value of positive integers, or  if less than 1. public static string Ordinal(this int number) { const string TH = "th"; string s = number.ToString(); // Negative and zero have no ordinal representation if (number < 1) { return s; } number %= 100; if ((number >= 11) && (number < = 13)) { return s + TH; } switch (number % 10) { case 1: return s + "st"; case 2: return s + "nd"; case 3: return s + "rd"; default: return s + TH; } } [Test] public void Ordinal_ReturnsExpectedResults() { Assert.AreEqual("-1", (1-2).Ordinal()); Assert.AreEqual("0", 0.Ordinal()); Assert.AreEqual("1st", 1.Ordinal()); Assert.AreEqual("2nd", 2.Ordinal()); Assert.AreEqual("3rd", 3.Ordinal()); Assert.AreEqual("4th", 4.Ordinal()); Assert.AreEqual("5th", 5.Ordinal()); Assert.AreEqual("6th", 6.Ordinal()); Assert.AreEqual("7th", 7.Ordinal()); Assert.AreEqual("8th", 8.Ordinal()); Assert.AreEqual("9th", 9.Ordinal()); Assert.AreEqual("10th", 10.Ordinal()); Assert.AreEqual("11th", 11.Ordinal()); Assert.AreEqual("12th", 12.Ordinal()); Assert.AreEqual("13th", 13.Ordinal()); Assert.AreEqual("14th", 14.Ordinal()); Assert.AreEqual("20th", 20.Ordinal()); Assert.AreEqual("21st", 21.Ordinal()); Assert.AreEqual("22nd", 22.Ordinal()); Assert.AreEqual("23rd", 23.Ordinal()); Assert.AreEqual("24th", 24.Ordinal()); Assert.AreEqual("100th", 100.Ordinal()); Assert.AreEqual("101st", 101.Ordinal()); Assert.AreEqual("102nd", 102.Ordinal()); Assert.AreEqual("103rd", 103.Ordinal()); Assert.AreEqual("104th", 104.Ordinal()); Assert.AreEqual("110th", 110.Ordinal()); Assert.AreEqual("111th", 111.Ordinal()); Assert.AreEqual("112th", 112.Ordinal()); Assert.AreEqual("113th", 113.Ordinal()); Assert.AreEqual("114th", 114.Ordinal()); Assert.AreEqual("120th", 120.Ordinal()); Assert.AreEqual("121st", 121.Ordinal()); Assert.AreEqual("122nd", 122.Ordinal()); Assert.AreEqual("123rd", 123.Ordinal()); Assert.AreEqual("124th", 124.Ordinal()); } 

    Você terá que rolar o seu próprio. Do alto da minha cabeça:

     public static string Ordinal(this int number) { var work = number.ToString(); if ((number % 100) == 11 || (number % 100) == 12 || (number % 100) == 13) return work + "th"; switch (number % 10) { case 1: work += "st"; break; case 2: work += "nd"; break; case 3: work += "rd"; break; default: work += "th"; break; } return work; } 

    Você pode então fazer

     Console.WriteLine(432.Ordinal()); 

    Editado para 11/12/13 exceções. Eu disse do topo da minha cabeça 🙂

    Editado para 1011 – outros corrigiram isso já, só quero ter certeza que os outros não pegam essa versão incorreta.

    Gostei bastante dos elementos das soluções de Stu e samjudson e trabalhei em conjunto no que penso ser uma combinação utilizável:

      public static string Ordinal(this int number) { const string TH = "th"; var s = number.ToString(); number %= 100; if ((number >= 11) && (number < = 13)) { return s + TH; } switch (number % 10) { case 1: return s + "st"; case 2: return s + "nd"; case 3: return s + "rd"; default: return s + TH; } } 

    Simples, limpo, rápido

      private static string GetOrdinalSuffix(int num) { if (num.ToString().EndsWith("11")) return "th"; if (num.ToString().EndsWith("12")) return "th"; if (num.ToString().EndsWith("13")) return "th"; if (num.ToString().EndsWith("1")) return "st"; if (num.ToString().EndsWith("2")) return "nd"; if (num.ToString().EndsWith("3")) return "rd"; return "th"; } 

    Ou melhor ainda, como um método de extensão

     public static class IntegerExtensions { public static string DisplayWithSuffix(this int num) { if (num.ToString().EndsWith("11")) return num.ToString() + "th"; if (num.ToString().EndsWith("12")) return num.ToString() + "th"; if (num.ToString().EndsWith("13")) return num.ToString() + "th"; if (num.ToString().EndsWith("1")) return num.ToString() + "st"; if (num.ToString().EndsWith("2")) return num.ToString() + "nd"; if (num.ToString().EndsWith("3")) return num.ToString() + "rd"; return num.ToString() + "th"; } } 

    Agora você pode apenas ligar

     int a = 1; a.DisplayWithSuffix(); 

    ou mesmo tão direto quanto

     1.DisplayWithSuffix(); 

    Embora ainda não tenha avaliado isso, você deve ser capaz de obter um melhor desempenho evitando todas as instruções de caso condicional.

    Isso é java, mas uma porta para C # é trivial:

     public class NumberUtil { final static String[] ORDINAL_SUFFIXES = { "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th" }; public static String ordinalSuffix(int value) { int n = Math.abs(value); int lastTwoDigits = n % 100; int lastDigit = n % 10; int index = (lastTwoDigits >= 11 && lastTwoDigits < = 13) ? 0 : lastDigit; return ORDINAL_SUFFIXES[index]; } public static String toOrdinal(int n) { return new StringBuffer().append(n).append(ordinalSuffix(n)).toString(); } } 

    Observe que a redução de condicionais e o uso da pesquisa de matriz deve acelerar o desempenho se gerar muitos ordinais em um loop estreito. No entanto, também admito que isso não é tão legível quanto a solução de declaração de caso.

    Semelhante à solução de Ryan, mas ainda mais básica, eu apenas uso uma matriz simples e uso o dia para procurar o ordinal correto:

     private string[] ordinals = new string[] {"","st","nd","rd","th","th","th","th","th","th","th","th","th","th","th","th","th","th","th","th","th","st","nd","rd","th","th","th","th","th","th","th","st" }; DateTime D = DateTime.Now; String date = "Today's day is: "+ D.Day.ToString() + ordinals[D.Day]; 

    Eu não tive a necessidade, mas eu suponho que você poderia usar uma multidimensional array se você quisesse ter suporte a vários idiomas.

    Pelo que me lembro dos meus dias de Uni, esse método exige um mínimo de esforço do servidor.

      private string getOrd(int num) { return $"{num}{(Range(11,3).Any(n => n == num % 100) ^ Range(1, 3).All(n => n != num%10) ? "th" : new[] { "st", "nd", "rd" }[num % 10-1])}"; } 

    Se alguém procura um forro: p

    Eu uso essa class de extensão:

     public static class Int32Extensions { public static string ToOrdinal(this int i) { return (i + "th") .Replace("1th", "1st") .Replace("2th", "2nd") .Replace("3th", "3rd"); } } 

    Solicitada versão “menos redundância” da resposta de samjudson …

     public static string AddOrdinal(int number) { if (number < = 0) return number.ToString(); string GetIndicator(int num) { switch (num % 100) { case 11: case 12: case 13: return "th"; } switch (num % 10) { case 1: return "st"; case 2: return "nd"; case 3: return "rd"; default: return "th"; } } return number + GetIndicator(number); } 

    FWIW, para MS-SQL, esta expressão fará o trabalho. Mantenha o primeiro WHEN ( WHEN num % 100 IN (11, 12, 13) THEN 'th' ) como o primeiro da lista, pois isso depende de ser julgado antes dos outros.

     CASE WHEN num % 100 IN (11, 12, 13) THEN 'th' -- must be tried first WHEN num % 10 = 1 THEN 'st' WHEN num % 10 = 2 THEN 'nd' WHEN num % 10 = 3 THEN 'rd' ELSE 'th' END AS Ordinal 

    Para o Excel:

     =MID("thstndrdth",MIN(9,2*RIGHT(A1)*(MOD(A1-11,100)>2)+1),2) 

    A expressão (MOD(A1-11,100)>2) é VERDADEIRO (1) para todos os números, com exceção de qualquer terminação em 11,12,13 (FALSO = 0). Então 2 * RIGHT(A1) * (MOD(A1-11,100)>2) +1) termina como 1 para 11/12/13, caso contrário:
    1 avalia a 3
    2 a 5,
    3 a 7
    outros: 9
    – e os 2 caracteres necessários são selecionados a partir de "thstndrdth" a partir dessa posição.

    Se você realmente quiser convertê-lo diretamente para SQL, isso funcionou para mim por alguns valores de teste:

     DECLARE @n as int SET @n=13 SELECT SubString( 'thstndrdth' , (SELECT MIN(value) FROM (SELECT 9 as value UNION SELECT 1+ (2* (ABS(@n) % 10) * CASE WHEN ((ABS(@n)+89) % 100)>2 THEN 1 ELSE 0 END) ) AS Mins ) , 2 ) 

    EDIT : Como YM_Industries aponta no comentário, a resposta do samjudson funciona para números acima de 1000, o comentário do nickf parece ter ido, e não me lembro qual foi o problema que eu vi. Deixou esta resposta aqui para os tempos de comparação.

    Muitos desses não funcionam para números> 999, como apontou Nickf em um comentário (EDIT: now missing).

    Aqui está uma versão baseada em uma versão modificada da resposta aceita pelo samjudson .

     public static String GetOrdinal(int i) { String res = ""; if (i > 0) { int j = (i - ((i / 100) * 100)); if ((j == 11) || (j == 12) || (j == 13)) res = "th"; else { int k = i % 10; if (k == 1) res = "st"; else if (k == 2) res = "nd"; else if (k == 3) res = "rd"; else res = "th"; } } return i.ToString() + res; } 

    Também a resposta de Shahzad Qureshi usando manipulação de strings funciona bem, mas tem uma penalidade de performance. Para gerar muitos desses, um programa de exemplo LINQPad torna a versão de string de 6 a 7 vezes mais lenta do que essa de número inteiro (embora você tenha que gerar muito para perceber).

    Exemplo do LINQPad:

     void Main() { "Examples:".Dump(); foreach(int i in new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 22, 113, 122, 201, 202, 211, 212, 2013, 1000003, 10000013 }) Stuff.GetOrdinal(i).Dump(); String s; System.Diagnostics.Stopwatch sw = System.Diagnostics.Stopwatch.StartNew(); for(int iter = 0; iter < 100000; iter++) foreach(int i in new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 22, 113, 122, 201, 202, 211, 212, 2013, 1000003, 1000013 }) s = Stuff.GetOrdinal(i); "Integer manipulation".Dump(); sw.Elapsed.Dump(); sw.Restart(); for(int iter = 0; iter < 100000; iter++) foreach(int i in new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 22, 113, 122, 201, 202, 211, 212, 2013, 1000003, 1000013 }) s = (i.ToString() + Stuff.GetOrdinalSuffix(i)); "String manipulation".Dump(); sw.Elapsed.Dump(); } public class Stuff { // Use integer manipulation public static String GetOrdinal(int i) { String res = ""; if (i > 0) { int j = (i - ((i / 100) * 100)); if ((j == 11) || (j == 12) || (j == 13)) res = "th"; else { int k = i % 10; if (k == 1) res = "st"; else if (k == 2) res = "nd"; else if (k == 3) res = "rd"; else res = "th"; } } return i.ToString() + res; } // Use string manipulation public static string GetOrdinalSuffix(int num) { if (num.ToString().EndsWith("11")) return "th"; if (num.ToString().EndsWith("12")) return "th"; if (num.ToString().EndsWith("13")) return "th"; if (num.ToString().EndsWith("1")) return "st"; if (num.ToString().EndsWith("2")) return "nd"; if (num.ToString().EndsWith("3")) return "rd"; return "th"; } } 
     public static string OrdinalSuffix(int ordinal) { //Because negatives won't work with modular division as expected: var abs = Math.Abs(ordinal); var lastdigit = abs % 10; return //Catch 60% of cases (to infinity) in the first conditional: lastdigit > 3 || lastdigit == 0 || (abs % 100) - lastdigit == 10 ? "th" : lastdigit == 1 ? "st" : lastdigit == 2 ? "nd" : "rd"; } 

    Baseado nas outras respostas:

     public static string Ordinal(int n) { int r = n % 100, m = n % 10; return (r<4 || r>20) && (m>0 && m<4) ? n+" stndrd".Substring(m*2,2) : n+"th"; } 

    Aqui está a class de extensão DateTime. Copie, cole e divirta-se

    class estática pública DateTimeExtensions {

      public static string ToStringWithOrdinal(this DateTime d) { var result = ""; bool bReturn = false; switch (d.Day % 100) { case 11: case 12: case 13: result = d.ToString("dd'th' MMMM yyyy"); bReturn = true; break; } if (!bReturn) { switch (d.Day % 10) { case 1: result = d.ToString("dd'st' MMMM yyyy"); break; case 2: result = d.ToString("dd'nd' MMMM yyyy"); break; case 3: result = d.ToString("dd'rd' MMMM yyyy"); break; default: result = d.ToString("dd'th' MMMM yyyy"); break; } } if (result.StartsWith("0")) result = result.Substring(1); return result; } } 

    Resultado:

    9 de outubro de 2014

    Outra alternativa que usei com base em todas as outras sugestões, mas não requer invólucro especial:

      public static string DateSuffix(int day) { if (day == 11 | day == 12 | day == 13) return "th"; Math.DivRem(day, 10, out day); switch (day) { case 1: return "st"; case 2: return "nd"; case 3: return "rd"; default: return "th"; } }