C # 'da ordinal oluşturmak için kolay bir yolu var mı?


202

C # bir sayı için Ordinals oluşturmak için kolay bir yolu var mı ? Örneğin:

  • 1 1 döndürür
  • 2 2. dönüş
  • 3 3 döndürür
  • ...vb

Bu yapılabilir String.Format()mi veya bunu yapmak için kullanılabilecek herhangi bir işlev var mı?

Yanıtlar:


312

Bu sayfa size tüm özel sayısal biçimlendirme kurallarının tam bir listesini verir:

http://msdn.microsoft.com/en-us/library/0c899ak8.aspx

Gördüğünüz gibi orada ordinaller hakkında hiçbir şey yok, bu yüzden String.Format kullanılarak yapılamaz. Ancak bunu yapmak için bir işlev yazmak o kadar da zor değil.

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

Güncelleme: Teknik = <0 için Ordinals mevcut değil, bu yüzden yukarıdaki kodu güncelledim. Ayrıca gereksiz ToString()yöntemler kaldırıldı .

Ayrıca, bunun uluslararasılaştırılmış olmadığını da unutmayın. Diğer dillerde ordinallerin nasıl göründüğü hakkında hiçbir fikrim yok.


2
Assert.AreEqual ("0", AddOrdinal (0)); Bkz wisegeek.com/what-is-an-ordinal-number.htm
si618

2
Bir uzatma yöntemi (veya adı ne olursa olsun - bkz. @ Stu'nun cevabı) burada harika çalışır. @Si, bu koşulu eklemek gerekirse çok kolay olurdu.
21'de strager

12
'11, 12, 13'ü unutmuşum ... bir röportaj sorusu olmalı. :-)
Holf

2
Evet, iyi programcılar tuhaf;)
samjudson

2
@IanWarburton Artıklık yoktur, çünkü yalnızca tek bir dönüş ifadesi vurulacaktır. Cevaptan memnun değilseniz, lütfen bunu kendiniz sağlayın ve bunu yapmanın "uygun" yolunu ve neden önemli olduğunu gösterin.
B2K

73

Uluslararasılaşmayı hatırlayın!

Buradaki çözümler yalnızca İngilizce için geçerlidir. Diğer dilleri desteklemeniz gerekiyorsa işler çok daha karmaşık hale gelir.

Örneğin, İspanyolcada "1.", saydığınız şeyin erkeksi, kadınsı veya çoğul olmasına bağlı olarak "1.o", "1.a", "1.os" veya "1.as" olarak yazılacaktır. !

Dolayısıyla, yazılımınızın farklı dilleri desteklemesi gerekiyorsa, sıra sıralarından kaçınmaya çalışın.


7
@ Andomar: "İlk 2 okuyucu" => İtalyanca (ve sanırım İspanyolca da) "ilk" burada çoğul. Yani tekil eril, tekil kadınsı, çoğul eril, çoğul dişil; belki bir dilin nötr bir durumu da vardır (şeyleri insanlardan / hayvanlardan ayıran)
M.Turrini

2
Bununla birlikte, sıra sıralarından kaçınmak zorunda değilsiniz: karşılaşabileceğiniz tüm vakayı öğrendikten veya (müşterinizi) bazı sınırlamaları kabul ettikten sonra bunları yerelleştirmeye dahil edin.
M.Turrini

26
Bu, .NET ekibinin DateTime biçimlendiricilerine neden eklemekten kaçındığını açıklar
Chris S

moment.js, yerel ayar tarafından "sıralı" bir biçimlendirme işlevine sahiptir, bu nedenle yapılabilir görünebilir, ayrıca DateTime için .NET'te yapmasını isterdim
Guillaume86

5
Hepiniz "." Almanca'da yaptığımız gibi sıra sıraları için karakter)))) 1. 2. 3. 4. 5., vb. 12 farklı kombinasyonun tekil ve çoğul hallerine ek olarak 3 farklı makaleli gramer vakaları. Düşünmeye gel, Rusların 2 tane daha yok, artı vokativ ve bazı İskandinav dillerinde 15 tane var sanırım. Bu uygulamayı .NET'te görmek isterdim.
Stefan Steiger

22

Jesse'nin Stu'nun ve Samjudson'un sürümleri versiyonum :)

Sayı <1 olduğunda kabul edilen cevabın yanlış olduğunu göstermek için dahil edilen ünite testi

    /// <summary>
    /// Get the ordinal value of positive integers.
    /// </summary>
    /// <remarks>
    /// 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
    /// </remarks>
    /// <param name="number">The number.</param>
    /// <returns>Ordinal value of positive integers, or <see cref="int.ToString"/> if less than 1.</returns>
    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());
    }

15

Basit, temiz, hızlı

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

Veya daha da iyisi, bir uzantı yöntemi olarak

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

Şimdi sadece

int a = 1;
a.DisplayWithSuffix(); 

hatta doğrudan

1.DisplayWithSuffix();

14

Kendinizi yuvarlamanız gerekecek. Başımın üstünden:

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

Sonra yapabilirsin

Console.WriteLine(432.Ordinal());

11/12/13 istisnalar için düzenlendi. Başımın üstünden söyledim :-)

1011 için düzenlendi - diğerleri bunu zaten düzeltti, sadece başkalarının bu yanlış sürümü yakalamadığından emin olmak istiyorum.


12

Doğrusu hem elemanları sevdim Stu 'ın ve samjudson ' ın çözümleri ve birlikte ben kullanılabilir bir combo olduğunu düşünüyorum içine çalıştı:

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

1
"th" için sabit kullanmanın ardındaki mantık nedir?
nickf

çünkü kodda iki kez kullanılır. Kendinizi tekrarlamamanız gereken eski bilgeliği kullanmak :) Bu durumda, .NET çalışma zamanı, kodda iki "th" ile birlikte dizenin yalnızca bir kopyasını oluşturmalı, iki dize oluşturulacaktır ve bellekte referans gösterilmektedir.
Jesse C. Slicer

25
ve ayrıca, TH değeri değişirse, ayarlanmış olursunuz.
Tutulma

7
@Jesse - + 1'imi alıyorsunuz, ancak .NET'in bu şekilde dizeleri işlediğine inanmıyorum, bkz. Yoda.arachsys.com/csharp/strings.html#interning , bu okumamın her biri "th" değişmezine yapılan atıf aynı hafızaya atıfta bulunur. Ama KURU hakkında katılıyorum :)
si618

4
Bunun gibi çoğaltmayı kaldırmak sadece okunabilirliği engeller, böylelikle "Neden TH?" DRY'nin 'maliyeti ne olursa olsun tüm kopyaları kaldır' olarak yorumlanması gerektiğini düşünmüyorum.
SeeNoWeevil

8

Bunu henüz kıyaslamamış olsam da, tüm koşullu vaka ifadelerinden kaçınarak daha iyi performans elde edebilmelisiniz.

Bu java, ancak C # için bir bağlantı noktası önemsiz:

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

Koşulların azaltılması ve dizi aramasının kullanılması, sıkı bir döngüde çok sayıda ordinal oluşturuyorsa performansı hızlandırmalıdır. Ancak, bunun durum bildirimi çözümü kadar okunabilir olmadığı konusunda da aynı fikirdeyim.


Üzgünüm, bunu C # ile kıyasladım, sürümünüz si618'in çözümünden daha hızlı değil.
GY_

bazı cevaplar için bu cevabı kontrol edin stackoverflow.com/a/58378465/2583579
Dan Dohotaru

3

Ryan'ın çözümüne benzer, ancak daha da temel, sadece düz bir dizi kullanıyorum ve günü doğru sıralamayı aramak için kullanıyorum:

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

İhtiyacım olmadı, ancak çoklu dil desteğine sahip olmak istiyorsanız çok boyutlu bir dizi kullanabileceğinizi varsayabilirim.

Uni günlerimden hatırlayabildiğim kadarıyla, bu yöntem sunucudan minimum çaba gerektirir.


2

Bu uzantı sınıfını kullanıyorum:

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

11, 12, 13
Kcoder

2

Samjudson'un cevabının "daha az yedeklilik" sürümü istendi ...

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

2
Ben "GetIndicator" olarak bir maruz public staticve daha anımsatıcı bir ad (yani "OrdinalSuffix") olarak yeniden adlandırmak. Arayan numarayı farklı biçimlerde (virgülle) isteyebilir.
Tom

2
        private static string GetOrd(int num) => $"{num}{(!(Range(11, 3).Any(n => n == num % 100) ^ Range(1, 3).All(n => n != num % 10)) ? new[] { "ˢᵗ", "ⁿᵈ", "ʳᵈ" }[num % 10 - 1] : "ᵗʰ")}";

Bir astar arayan biri varsa: p


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

1

DÜZENLEME : YM_Industries yorumda belirtildiği gibi, samjudson'un cevabı 1000'in üzerindeki sayılar için işe yarıyor, nickf'in yorumu gitmiş gibi görünüyor ve gördüğüm sorunun ne olduğunu hatırlayamıyorum. Karşılaştırma zamanlamaları için bu cevabı burada bıraktı.

Bunların çok büyük bir kısmı , bir yorumda nickf'in işaret ettiği gibi 999'dan büyük sayılar için işe yaramaz (EDIT: şimdi eksik).

İşte değiştirilmiş bir versiyonu kapalı tabanlı bir sürümüdür samjudson 's kabul edilen cevap yok.

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

Ayrıca Shahzad Kureyşi 'ın cevabı dize kullanımı kullanarak bir performans ceza var ancak cezası çalışır. Bunların çoğunu oluşturmak için, bir LINQPad örnek programı, dize sürümünü bu tamsayıdan 6-7 kat daha yavaş yapar (ancak dikkat edilmesi gereken çok şey oluşturmanız gerekir).

LINQPad örneği:

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

@ Nickf'in yorumunu bulamıyorum, samjudson'un cevabı nedir? Bana göre 1000'den fazla sayıları gayet iyi işlerken sizinkinden çok daha okunabilir gibi görünüyor.
Joshua Walsh

1
Bu adil bir yorum, sadece bir test seti çalıştırdım ve herhangi bir sorun bulamıyorum. Sam'in cevabında da herhangi bir düzenleme yapılmadığı için sadece delirdiğimi hayal edebiliyorum. Cevabımı bunu yansıtacak şekilde düzenledim.
Whelkaholism

1
Haha, hepimizin böyle anları var değil mi? Eski koda tekrar bakıp "Neden bunu yazdım?"
Joshua Walsh

1

Diğer cevaplara dayanarak:

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

3
1. YER: En Gereksiz Şifreli Cevap. "Gereksiz yere": Kod boyutu / performansı, okunabilirlik maliyetlerine değmez. "Cryptic": "Layperson" Gereksinimleri ile eşleştirmek için önemli çeviri gerekir.
Tom

1

Burada çok sayıda iyi cevap olsa da, başka bir şey için yer var, bu sefer desen eşleşmesine dayanıyor, başka bir şey için değilse, en azından tartışmalı okunabilirlik için

    public static string Ordinals1(this int number)
    {
        switch (number)
        {
            case int p when p % 100 == 11:
            case int q when q % 100 == 12:
            case int r when r % 100 == 13:
                return $"{number}th";
            case int p when p % 10 == 1:
                return $"{number}st";
            case int p when p % 10 == 2:
                return $"{number}nd";
            case int p when p % 10 == 3:
                return $"{number}rd";
            default:
                return $"{number}th";
        }
    }

ve bu çözümü özel yapan nedir? diğer çeşitli çözümler için bazı performans değerlendirmeleri eklediğimden başka bir şey yok

Açıkçası performansın bu özel senaryo için gerçekten önemli olduğundan şüpheliyim (milyonlarca sayının ordinallerine gerçekten ihtiyaç duyan) ama en azından dikkate alınması gereken bazı karşılaştırmalar var ...

Referans için 1 milyon ürün (köyünüz elbette makine özelliklerine göre değişebilir)

örüntü eşleme ve bölümlerle (bu cevap)

~ 622 ms

kalıp eşleme ve dizgilerle (bu cevap)

~ 1967 ms

iki anahtar ve bölmeli (kabul edilen cevap)

~ 637 ms

bir anahtar ve bölümlerle (başka bir cevap)

~ 725 ms

void Main()
{
    var timer = new Stopwatch();
    var numbers = Enumerable.Range(1, 1000000).ToList();

    // 1
    timer.Reset();
    timer.Start();
    var results1 = numbers.Select(p => p.Ordinals1()).ToList();
    timer.Stop();
    timer.Elapsed.TotalMilliseconds.Dump("with pattern matching and divisions");

    // 2
    timer.Reset();
    timer.Start();
    var results2 = numbers.Select(p => p.Ordinals2()).ToList();
    timer.Stop();
    timer.Elapsed.TotalMilliseconds.Dump("with pattern matching and strings");

    // 3
    timer.Reset();
    timer.Start();
    var results3 = numbers.Select(p => p.Ordinals3()).ToList();
    timer.Stop();
    timer.Elapsed.TotalMilliseconds.Dump("with two switches and divisons");

    // 4
    timer.Reset();
    timer.Start();
    var results4 = numbers.Select(p => p.Ordinals4()).ToList();
    timer.Stop();
    timer.Elapsed.TotalMilliseconds.Dump("with one switche and divisons");
}

public static class Extensions
{
    public static string Ordinals1(this int number)
    {
        switch (number)
        {
            case int p when p % 100 == 11:
            case int q when q % 100 == 12:
            case int r when r % 100 == 13:
                return $"{number}th";
            case int p when p % 10 == 1:
                return $"{number}st";
            case int p when p % 10 == 2:
                return $"{number}nd";
            case int p when p % 10 == 3:
                return $"{number}rd";
            default:
                return $"{number}th";
        }
    }

    public static string Ordinals2(this int number)
    {
        var text = number.ToString();
        switch (text)
        {
            case string p when p.EndsWith("11"):
                return $"{number}th";
            case string p when p.EndsWith("12"):
                return $"{number}th";
            case string p when p.EndsWith("13"):
                return $"{number}th";
            case string p when p.EndsWith("1"):
                return $"{number}st";
            case string p when p.EndsWith("2"):
                return $"{number}nd";
            case string p when p.EndsWith("3"):
                return $"{number}rd";
            default:
                return $"{number}th";
        }
    }

    public static string Ordinals3(this int number)
    {
        switch (number % 100)
        {
            case 11:
            case 12:
            case 13:
                return $"{number}th";
        }

        switch (number % 10)
        {
            case 1:
                return $"{number}st";
            case 2:
                return $"{number}nd";
            case 3:
                return $"{number}rd";
            default:
                return $"{number}th";
        }
    }

    public static string Ordinals4(this int number)
    {
        var ones = number % 10;
        var tens = Math.Floor(number / 10f) % 10;
        if (tens == 1)
        {
            return $"{number}th";
        }

        switch (ones)
        {
            case 1:
                return $"{number}th";
            case 2:
                return $"{number}nd";
            case 3:
                return $"{number}rd";
            default:
                return $"{number}th";
        }
    }
}

0

FWIW, MS-SQL için bu ifade işi yapacak. İlk WHEN ( WHEN num % 100 IN (11, 12, 13) THEN 'th') i listede ilk olan olarak saklayın , çünkü bu diğerlerinden önce denenmeye dayanır.

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

Excel için:

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

(MOD(A1-11,100)>2)İçinde herhangi bir son hariç tüm sayılar için ifade TRUE (1) olur11,12,13 (FALSE = 0) ile ) olur. Yani 2 * RIGHT(A1) * (MOD(A1-11,100)>2) +1)11/12/13 için 1 olarak biter, aksi takdirde:
1 3
2 ila 5,
3 ila 7
diğerlerini değerlendirir: 9
- ve "thstndrdth"bu konumdan başlayarak gerekli 2 karakter seçilir .

Bunu gerçekten doğrudan SQL'e dönüştürmek istiyorsanız, bu benim için birkaç test değeri için çalıştı:

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
                )

0

Bu uygulamadaki dartdildir ve dile göre değiştirilebilir.

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

0

Başka bir tek astar, ancak regex sonucunu bir diziye endeksleyerek karşılaştırmalar olmadan.

public static string GetOrdinalSuffix(int input)
{
    return new []{"th", "st", "nd", "rd"}[Convert.ToInt32("0" + Regex.Match(input.ToString(), "(?<!1)[1-3]$").Value)];
}

PowerShell sürümü daha da kısaltılabilir:

function ord($num) { return ('th','st','nd','rd')[[int]($num -match '(?<!1)[1-3]$') * $matches[0]] }

0

Başka 1 astar.

public static string Ordinal(this int n)
{    
 return n + (new [] {"st","nd","rd" }.ElementAtOrDefault((((n + 90) % 100 - 10) % 10 - 1)) ?? "th");
}

-2

İşte DateTime Extension sınıfı. Kopyala, Yapıştır ve Keyfini Çıkar

public static class 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;
    }
}

Sonuç:

9 Ekim 2014


Yineliyorsunuz: a) Tarih Biçimi Dizesi (X5) ve b) Yöntemin geri kalanının tamamı (olası Kullanım Durumu ortaya çıktığında (henüz oluşturulmamışsa) Ayın Günü için sıralı bir sonek gerektiği anlamına gelir amaçlar veya hatta farklı bir Tarih Biçimi Dizesi ile Ayın Günü). Ian Warburton'ın 6 Nisan 1717'de 16:32 yanıtında ( stackoverflow.com/questions/20156/… ) gösterilmesini önerdiğim "OrdinalSuffix" Yöntemini kullanın .
Tom

-3

Diğer tüm önerilere dayanarak kullandığım, ancak özel bir kasa gerektirmeyen başka bir alternatif:

    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";
        }
    }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.