Есть ли в .NET простой способ получить окончания «st», «nd», «rd» и «th» для чисел?

Мне интересно, есть ли метод или строка формата, которую мне не хватает в .NET, чтобы преобразовать следующее:

   1 to 1st
   2 to 2nd
   3 to 3rd
   4 to 4th
  11 to 11th
 101 to 101st
 111 to 111th

У Эта ссылка есть плохой пример основного принципа, задействованного в написании вашей собственной функции, но мне более любопытно, есть ли встроенная емкость, которой мне не хватает.

Решение

Ответ Скотта Хансельмана принят, потому что он дает прямой ответ на вопрос.

Однако для решения см. этот отличный ответ.

Они называются порядковыми числами (1-е, 2-е и т. д.) В отличие от количественных чисел (1,2,3 и т. д.), К вашему сведению.

pc1oad1etter 16.09.2008 08:15

Здесь был дан довольно элегантный ответ: stackoverflow.com/questions/20156/ordinals-in-c#

Portman 17.09.2008 18:32
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
69
2
50 090
11
Перейти к ответу Данный вопрос помечен как решенный

Ответы 11

Ответ принят как подходящий

Нет, в библиотеке базовых классов .NET нет встроенных возможностей.

Это запоздалый комментарий, но есть ли планы добавить эту возможность в .NET BCL для форматирования дат?

Breakskater 19.05.2013 20:09

Как насчет сейчас, в 2019 году?

Imad 04.04.2019 10:23

Это функция намного проще, чем вы думаете. Хотя для этого может уже существовать функция .NET, следующая функция (написанная на PHP) выполняет свою работу. Перенести это не должно быть слишком сложно.

function ordinal($num) {
    $ones = $num % 10;
    $tens = floor($num / 10) % 10;
    if ($tens == 1) {
        $suff = "th";
    } else {
        switch ($ones) {
            case 1 : $suff = "st"; break;
            case 2 : $suff = "nd"; break;
            case 3 : $suff = "rd"; break;
            default : $suff = "th";
        }
    }
    return $num . $suff;
}

А как насчет локализации?

macbirdie 17.09.2008 01:26

Локализация будет означать, что вам придется создавать отдельные функции для каждого языка. В немецком языке вы можете просто добавить «тер», но «1тер» «2тер» «3тер» выглядит очень плохо, даже несмотря на то, что это грамматически правильно. На французском немного лучше, но универсального способа для каждого языка нет.

Michael Stum 17.09.2008 13:14

@Michael Stum: Я не слишком знаком со всеми международными порядковыми форматами, но будет ли достаточно string.Format (resString, number)? Или в некоторых языках числа не сочетаются с порядковыми (пре / суффикс) индексами?

Matt Mitchell 21.06.2010 09:15

@MichaelStum: На самом деле на немецком языке нельзя просто добавить «тер». Рассмотрим "Heute ist der 1te Januar" (сегодня 1 января). Или «Klicken Sie den 5ten Button» (нажмите 5-ю кнопку). Назовем лишь два из десятков случаев. Вы должны учитывать правильное сгибание (англ. Изгиб) для каждого использования.

Regexident 26.01.2012 17:04

Сочетание числа и такого суффикса необычно для немецкого языка. Вы либо напишите это как «1». или "эрстер" / "эрсте". Последний обычно используется в текстах, и его редко нужно генерировать автоматически.

CodesInChaos 06.06.2014 14:03

Разве это не подведет для чисел от 10 до 20?

dannio 17.08.2015 10:56

@dannio Нет, есть условие для $tens

Rufus L 14.11.2019 00:23

Это уже было рассмотрено, но я не знаю, как на это ссылаться Вот фрагмент кода:

    public static string Ordinal(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 + "st";
            case 2: return number + "nd";
            case 3: return number + "rd";
            default: return number + "th";
        }
    }

К вашему сведению: это метод расширения. Если ваша версия .NET меньше 3.5, просто удалите это ключевое слово

[РЕДАКТИРОВАТЬ]: Спасибо, что указали, что это неверно, это то, что вы получаете за копирование / вставку кода :)

Не работает. 1011% 10 == 1. 1011-е неверно.

Matt Mitchell 16.09.2008 08:00

Мне нравится, как вы объявляете переменную ones и никогда ее не используете.

John Gietzen 09.05.2009 00:14

@MattMitchell В вашем примере это будет 10110-й, а не 1011-й

eoleary 30.04.2013 19:03

@EOLeary не уверен, что вы говорите, но я думаю, что редактирование Маршалла послужило моему примеру.

Matt Mitchell 30.04.2013 19:49

Зачем использовать float вместо простых целых чисел? Я бы использовал (number / 10) % 10.

CodesInChaos 06.06.2014 14:06

Нет необходимости использовать Math.Floor; деление отбрасывает десятичные дроби, если оба числа - int. Следует читать как var tens = number / 10 % 10;.

Pluto 30.10.2019 22:28

Я думаю, что порядковый суффикс трудно получить ... вам в основном нужно написать функцию, которая использует переключатель для проверки чисел и добавления суффикса.

У языка нет причин предоставлять это внутренне, особенно когда он зависит от локали.

Вы можете сделать немного лучше, чем эта ссылка, когда дело доходит до количества кода для написания, но вам нужно написать функцию для этого ...

Учитывая все строки локализации валюты и т. д., Добавление порядкового суффикса кажется немного натянутым.

Matt Mitchell 16.09.2008 08:06

@nickf: Вот функция PHP на C#:

public static string Ordinal(int number)
{
    string suffix = String.Empty;

    int ones = number % 10;
    int tens = (int)Math.Floor(number / 10M) % 10;

    if (tens == 1)
    {
        suffix = "th";
    }
    else
    {
        switch (ones)
        {
            case 1:
                suffix = "st";
                break;

            case 2:
                suffix = "nd";
                break;

            case 3:
                suffix = "rd";
                break;

            default:
                suffix = "th";
                break;
        }
    }
    return String.Format("{0}{1}", number, suffix);
}

Ха, спасибо, вот-вот отправлю код, который я написал. Думаю, ваш в любом случае превосходит мой с битом String.Format.

Matt Mitchell 16.09.2008 08:21

1) Почему перевод в десятичный? Простой (number / 10) % 10 делает свое дело. 2) Почему вы инициализируете suffix значением, которое никогда не будет использоваться?

CodesInChaos 06.06.2014 14:05

@CodesInChaos: без преобразования в десятичный формат вы получите ошибку компилятора: The call is ambiguous between the following methods or properties: 'System.Math.Floor(decimal)' and 'System.Math.Floor(double)'. Инициализация suffix на String.Empty в основном является привычкой, но также помогает избежать случайных ошибок Use of unassigned local variable 'suffix'.

Scott Dorman 06.06.2014 16:58

@ScottDorman 1) Только если вы оставите вызов Floor, что бессмысленно для целых чисел. Целочисленное деление просто обрезается до нуля, нет необходимости приводить к десятичному виду или использовать Floor. (number / 10) % 10 попроще и работает. 2) Эти ошибки возникают, если вы пропустили путь кода. Ошибка компилятора говорит вам исправить эту ошибку вместо того, чтобы молча возвращать бесполезное значение.

CodesInChaos 06.06.2014 17:05

else if (choice=='q')
{
    qtr++;

    switch (qtr)
    {
        case(2): strcpy(qtrs,"nd");break;
        case(3):
        {
           strcpy(qtrs,"rd");
           cout<<"End of First Half!!!";
           cout<<" hteam "<<"["<<hteam<<"] "<<hs;
           cout<<" vteam "<<" ["<<vteam;
           cout<<"] ";
           cout<<vs;dwn=1;yd=10;

           if (beginp=='H') team='V';
           else             team='H';
           break;
       }
       case(4): strcpy(qtrs,"th");break;

Ну давай же. что ты пишешь? Это не имеет ничего общего с моим вопросом.

santubangalore 27.06.2014 08:42

Вот версия функции Microsoft SQL Server:

CREATE FUNCTION [Internal].[GetNumberAsOrdinalString]
(
    @num int
)
RETURNS nvarchar(max)
AS
BEGIN

    DECLARE @Suffix nvarchar(2);
    DECLARE @Ones int;  
    DECLARE @Tens int;

    SET @Ones = @num % 10;
    SET @Tens = FLOOR(@num / 10) % 10;

    IF @Tens = 1
    BEGIN
        SET @Suffix = 'th';
    END
    ELSE
    BEGIN

    SET @Suffix = 
        CASE @Ones
            WHEN 1 THEN 'st'
            WHEN 2 THEN 'nd'
            WHEN 3 THEN 'rd'
            ELSE 'th'
        END
    END

    RETURN CONVERT(nvarchar(max), @num) + @Suffix;
END

Я только что написал эту функцию почти дословно! Различия: master db, cast вместо convert, и я использую немного другой отступ. Думаю, великие умы ...

John Gietzen 09.05.2009 00:21

+1 - Просто была потребность в версии SQL - спасло меня, написав одну

HeavenCore 26.04.2012 18:15

Превосходно, но только если мы получаем данные из SQL. Но в этом случае я форматирую переменную DateTime .net. Но эта функция будет безмерно полезной.

santubangalore 27.06.2014 08:45

Я знаю, что это не ответ на вопрос OP, но поскольку я счел полезным вывести функцию SQL Server из этого потока, вот эквивалент Delphi (Pascal):

function OrdinalNumberSuffix(const ANumber: integer): string;
begin
  Result := IntToStr(ANumber);
  if (((Abs(ANumber) div 10) mod 10) = 1) then // Tens = 1
    Result := Result + 'th'
  else
    case(Abs(ANumber) mod 10) of
      1: Result := Result + 'st';
      2: Result := Result + 'nd';
      3: Result := Result + 'rd';
      else
        Result := Result + 'th';
    end;
end;

Имеет ли смысл ..., -1, 0?

Просто, чисто, быстро

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

Или еще лучше, как метод расширения

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

Теперь ты можешь просто вызвать

int a = 1;
a.DisplayWithSuffix(); 

или даже прямо как

1.DisplayWithSuffix();

Наверное, самый изящный ответ здесь.

Matt Mitchell 24.10.2013 08:36

Я думаю это самый чистый способ сделать это

Serj Sagan 30.04.2014 04:59

Несомненно лучший ответ. На самом деле это полагается на число как на текст, а не на сложную математическую формулу. Именно так бы это понял сам человеческий мозг, и это идеально.

Chris Pratt 12.09.2014 19:19

Это хороший ответ, но если метод называется DisplayWithSuffix, то возвращаемый ответ должен включать число, чтобы 1 возвращал «1st», а не просто «st».

HitLikeAHammer 22.10.2014 21:38

Хорошее замечание, HitLikeAHammer. Я настрою код, чтобы отразить это.

Shahzad Qureshi 27.10.2014 20:11

Вероятно, вы захотите поместить num.ToString() в переменную. Не уверен, что кто-то посчитал бы этот ответ простым, понятным или быстрым, если честно.

Rudey 08.12.2018 22:50

@Rudey Точно, -1.

Ondrej Tucny 13.11.2019 23:11

Другой аромат:

/// <summary>
/// Extension methods for numbers
/// </summary>
public static class NumericExtensions
{
    /// <summary>
    /// Adds the ordinal indicator to an integer
    /// </summary>
    /// <param name = "number">The number</param>
    /// <returns>The formatted number</returns>
    public static string ToOrdinalString(this int number)
    {
        // Numbers in the teens always end with "th"

        if ((number % 100 > 10 && number % 100 < 20))
            return number + "th";
        else
        {
            // Check remainder

            switch(number % 10)
            {
                case 1:
                    return number + "st";

                case 2:
                    return number + "nd";

                case 3:
                    return number + "rd";

                default:
                    return number + "th";
            }
        }
    }
}

Собственно хороший ответ. Но он общий, то есть не относится к датам месяца. Я имел в виду только свидания. Таким образом, значение выше 100 может быть неприменимо.

santubangalore 27.06.2014 08:44

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

Другие вопросы по теме