Чи є простий спосіб створення порядків у C #?


202

Чи є в C # простий спосіб створити ординари для числа? Наприклад:

  • 1 повертає 1-е
  • 2 повертає 2-е
  • 3 повертає 3-е
  • ... тощо

Чи можна це зробити через String.Format()чи є для цього доступні функції?

Відповіді:


310

На цій сторінці ви знайдете повний перелік усіх спеціальних правил форматування чисел:

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

Як бачимо, там немає нічого про порядкові порядки, тому це неможливо зробити за допомогою String.Format. Однак не дуже важко написати функцію, щоб це зробити.

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

Оновлення: технічно ординари не існують для <= 0, тому я оновив код вище. Також видалено зайві ToString()методи.

Також зауважте, це не є інтернаціоналізованим. Я поняття не маю, як виглядають ординари на інших мовах.


2
Assert.AreEqual ("0", AddOrdinal (0)); Перегляньте mudgeek.com/what-is-an-ordinal-number.htm
si618

2
Використання методу розширення (або як воно ще називається - див. Відповідь @ Стю) тут би чудово працювало. @Si, Додавання цієї умови було б дуже просто, якщо вона потрібна.
страгер

12
Забув про "11, 12 13" ... має бути питанням інтерв'ю. :-)
Холф

2
Так, добре програмісти дивні;)
samjudson

2
@IanWarburton Немає надмірності, оскільки буде потрапляти лише одна заява про повернення. Якщо ви не задоволені відповіддю, будь ласка, надайте свій власний, показавши нам "правильний" спосіб цього зробити, і чому це має значення.
B2K

73

Пам’ятайте про інтернаціоналізацію!

Рішення тут працюють лише для англійської мови. Речі стають набагато складнішими, якщо вам потрібно підтримувати інші мови.

Наприклад, іспанською мовою "1-й" буде писатись як "1.o", "1.a", "1.os" або "1.as", залежно від того, що ви рахуєте - чоловіче, жіноче або множинне !

Тож якщо вашому програмному забезпеченню потрібно підтримувати різні мови, намагайтеся уникати порядків.


7
@ Andomar: "Перші 2 читачі" => італійською мовою (і, імовірно, теж) "перший" тут множиною. Отже, у вас є однина чоловічого роду, однини жіночого роду, множини чоловічого роду, множини жіночого роду; можливо, в деяких мовах є також нейтральний випадок (відмінність речей від чоловіків / тварин)
М.Турріні

2
Однак, вам не доведеться уникати порядкових записів: включіть їх у локалізацію, як тільки ви дізнаєтесь про всі випадки, з якими ви могли зіткнутися, або (змусити свого замовника) прийняти деякі обмеження.
М.Турріні

26
Це пояснює, чому команда .NET відмовилася від того, щоб додати її до форматорів DateTime
Chris S

moment.js має функцію "порядкового" форматування за локальною ознакою, тому здається здійсненною, також бажаю, щоб вони зробили це в .NET for DateTime
Guillaume86

5
Все було б дуже просто, якби ви всі використовували "". символ для простих порядків, як це робимо німецькою мовою)))) 1. 2. 3. 4. 5. і т. д. Хоча алгоритм був би набагато цікавішим, якби виписати число, і додати переклад через 4 граматичні відмінки з 3 різними статтями, окрім однини та множини від 12 різних комбінацій. Подумайте про те, чи не мають у росіян ще 2 плюс vocativ, а деякі нордичні мови мають 15, я думаю. Я хотів би бачити цю реалізацію в .NET.
Стефан Штайгер

22

Моя версія версії Джессі щодо Сту та Самюдсона :)

Тест одиниці включений, щоб показати, що прийнята відповідь неправильна, коли число <1

    /// <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

Простий, чистий, швидкий

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

Або ще краще, як метод розширення

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

Тепер ви можете просто зателефонувати

int a = 1;
a.DisplayWithSuffix(); 

або навіть так прямо, як

1.DisplayWithSuffix();

14

Вам доведеться прокатати своє. Зверху голови:

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

Потім ви можете зробити

Console.WriteLine(432.Ordinal());

Відредаговано за винятками 11.12.13. Я РОЗПОВІСТЮ кажу з верхньої частини голови :-)

Відредаговано для 1011 року - інші це вже виправили, просто хочуть переконатися, що інші не схоплять цю неправильну версію.


12

Мені швидше сподобалися елементи з рішень Сту та Самюдсона , і я спільно працював над тим, що, на мою думку, є корисним комбо:

    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
яке обґрунтування використання константи для "го"?
нікфф

тому що він використовується в коді двічі. Просто використовуючи вікову мудрість, яку не слід повторювати :) У цьому випадку .NET час виконання повинен створювати лише одну копію рядка, в той час як з кодом два "th", створено два рядки і посилаються на пам'ять.
Jesse C. Slicer

25
а також, якщо значення TH колись зміниться, вам буде встановлено.
Затемнення

7
@Jesse - Ви отримуєте мій +1, але я не вірю. NET обробляє рядки таким чином, див. Yoda.arachsys.com/csharp/strings.html#interning , моє читання - це кожне посилання на "й" буквал посилався б на той самий біт пам'яті. Але я погоджуюсь щодо DRY :)
si618

4
Видалення дублювання, як це, просто перешкоджає читанню, я думаю, звідси плутанина "Чому TH?". Я не думаю, що DRY не слід тлумачити як "видалити всі дублювання незалежно від вартості".
SeeNoWeevil

8

Хоча я ще цього не оцінював, ви повинні мати можливість досягти кращих показників, уникаючи всіх умовних заяв.

Це Java, але порт на C # є тривіальним:

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

Зауважте, зменшення умовних умов та використання пошуку масиву повинно прискорити продуктивність, якщо генерується багато порядкових знаків у тісному циклі. Однак я також визнаю, що це не так читабельно, як рішення заяви справи.


Вибачте, що я позначив це на C #, ваша версія не швидша за рішення si618.
GY_

Перевірте цю відповідь stackoverflow.com/a/58378465/2583579 на тестування деяких тестів
Dan

3

Подібно до рішення Райана, але ще більш базового, я просто використовую звичайний масив і використовую день, щоб шукати правильний порядковий номер:

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

У мене не було потреби, але я вважаю, що ви могли б використовувати багатовимірний масив, якби хотіли мати підтримку декількох мов.

Оскільки я пам’ятаю свої дні в Uni, цей метод вимагає мінімальних зусиль з боку сервера.


2

Я використовую цей клас розширення:

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

Запитувана версія "менш зайвої" версії відповіді самджудсона ...

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
Я би виставив "GetIndicator" як a public staticі перейменував би його на більш мнемічне ім'я (тобто "OrdinalSuffix"). Користувач може захотіти, щоб числова частина була в різних форматах (тобто з комами).
Том

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] : "ᵗʰ")}";

Якщо хтось шукає один лайнер: 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

EDIT : Як у коментарі зазначає YM_Industries, відповідь samjudson працює на цифри понад 1000, коментар нікефа, схоже, пішов, і я не можу пригадати, у чому була проблема. Залишив цю відповідь тут для часу порівняння.

Дуже багато з них не працюють для цифр> 999, як нікфф зазначив у коментарі (EDIT: зараз відсутнє).

Ось версія , заснована від модифікованої версії 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;
}

Також Шахзад Куреши «s відповідь з допомогою маніпуляцій з рядками працює відмінно, однак у нього є зниження продуктивності. Для генерації багатьох з них програма прикладу LINQPad робить версію рядка в 6-7 разів повільнішою, ніж ціле ціле (хоча вам доведеться генерувати багато, щоб помітити).

Приклад 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";
        }
}

Я не можу знайти коментар @ nickf, що не так з відповіддю samjudson? Мені здається, він обробляє цифри вище 1000 просто чудово, в той час як набагато читає, ніж твій.
Джошуа Уолш

1
Це чесний коментар, я просто запустив тестовий набір і не можу знайти жодних проблем. Здається, відповіді Сема не було жодних змін, тому я можу лише уявити, що я зійшов з розуму. Я відредагував свою відповідь, щоб це відобразити.
Whelkaholism

1
Ха-ха, у всіх нас є такі моменти, чи не так? Ми озираємося на старий код і переходимо "чому, до чорта я це написав?"
Джошуа Уолш

1

Виходячи з інших відповідей:

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 МІСЦЕ: Найнеобхідніший скептичний відповідь. "Потрібно": переваги розміру коду / продуктивності не варто витрачати на читабельність. "Криптовалюта": Значний переклад потрібен для відображення вимог до "Лайперсона".
Том

0

FWIW, для MS-SQL цей вираз зробить роботу. Зберігайте перший WHEN ( WHEN num % 100 IN (11, 12, 13) THEN 'th') як перший у списку, оскільки це покладається на спробу перед іншими.

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:

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

Вираз (MOD(A1-11,100)>2)TRUE (1) для всіх чисел, крім будь-якого, що закінчується 11,12,13(FALSE = 0). Так 2 * RIGHT(A1) * (MOD(A1-11,100)>2) +1)закінчується 1 за 11.12.13, інакше:
1 оцінює 3
2 до 5,
3 - 7
інших: 9
- і потрібні 2 символи вибираються "thstndrdth"починаючи з цієї позиції.

Якщо ви дійсно хочете перетворити це досить безпосередньо в SQL, це працювало для мене для кількох тестових значень:

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

Це реалізація в dartі може бути змінена відповідно до мови.

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

Хоча тут є багато хороших відповідей, я думаю, що є місце для іншого, цього разу на основі відповідності шаблонів, якщо не для іншого, то принаймні для дискусійної читабельності

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

і що робить це рішення особливим? нічого, крім того, що я додаю деякі міркування щодо ефективності для різних інших рішень

відверто кажучи, я сумніваюся, що ефективність дійсно має значення для цього конкретного сценарію (кому дійсно потрібні порядкові мільйони чисел), але, принаймні, це деякі порівняння, які слід враховувати ...

1 мільйон предметів для довідки (ваш фрезер може змінюватися залежно від технічних характеристик, звичайно)

з узгодженням шаблонів та поділами (ця відповідь)

~ 622 мс

з узгодженням шаблону та рядками (ця відповідь)

~ 1967 мс

з двома перемикачами та відділеннями (прийнята відповідь)

~ 637 мс

з одним перемикачем і діленнями (інша відповідь)

~ 725 мс

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

Інший однолінійний, але без порівнянь, лише індексуючи регулярний вираз, перетворюється на масив.

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

Версію PowerShell можна додатково скоротити:

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

0

Ще 1 вкладиш.

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

-2

Ось клас розширення DateTime. Копіюйте, вставляйте та насолоджуйтесь

загальнодоступний статичний клас 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;
    }
}

Результат:

9 жовтня 2014 року


Ви дублюєте: а) рядок формату дати (X5) та б) весь решта методу (коли виникає ймовірний випадок використання (якщо він ще не був), що порядковий суфікс потрібен для недення місяця цілі або навіть день місяця з іншим рядком формату дати). Скористайтеся методом "OrdinalSuffix", який я запропонував викрити від відповіді Яна Варбуртона 6 квітня 1717 року о 16:32 ( stackoverflow.com/questions/20156/… ).
Том

-3

Ще одна альтернатива, яку я використав, грунтуючись на всіх інших пропозиціях, але не потребує спеціального корпусу:

    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";
        }
    }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.