Есть ли в .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

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

Решение

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

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


person Matt Mitchell    schedule 16.09.2008    source источник
comment
Они называются порядковыми числами (1-е, 2-е и т. Д.) В отличие от количественных чисел (1,2,3 и т. Д.), К вашему сведению.   -  person pc1oad1etter    schedule 16.09.2008
comment
Здесь был дан довольно элегантный ответ: stackoverflow.com/questions/20156/ordinals-in-c#   -  person Portman    schedule 17.09.2008


Ответы (10)


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

person Scott Hanselman    schedule 16.09.2008
comment
Это запоздалый комментарий, но есть ли планы добавить эту возможность в .NET BCL для форматирования дат? - person Breakskater; 19.05.2013
comment
Как насчет сейчас, в 2019 году? - person Imad; 04.04.2019

Это функция намного проще, чем вы думаете. Хотя для этого может уже существовать функция .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;
}
person nickf    schedule 16.09.2008
comment
А как насчет локализации? - person macbirdie; 17.09.2008
comment
Локализация будет означать, что вам придется создавать отдельные функции для каждого языка. На немецком языке вы можете просто добавить тер, но 1ter 2ter 3ter выглядит очень плохо, даже несмотря на то, что это грамматически правильно. На французском немного лучше, но универсального способа для каждого языка нет. - person Michael Stum; 17.09.2008
comment
@Michael Stum: Я не слишком знаком со всеми международными порядковыми форматами, но будет ли достаточно string.Format (resString, number)? Или в некоторых языках числа не сочетаются с порядковыми (пред / суффикс) индексами? - person Matt Mitchell; 21.06.2010
comment
@MichaelStum: На самом деле на немецком языке нельзя просто добавить тер. Рассмотрим Heute ist der 1te Januar (сегодня 1 января). Или Klicken Sie den 5ten Button (нажмите 5-ю кнопку). Назовем лишь два из десятков случаев. Вы должны учитывать правильное сгибание (англ. Изгиб) для каждого использования. - person Regexident; 26.01.2012
comment
Сочетание числа и такого суффикса необычно для немецкого языка. Вы либо пишете как 1., либо как erster / erste. Последний обычно используется в текстах, и его редко нужно генерировать автоматически. - person CodesInChaos; 06.06.2014
comment
Разве это не подведет для чисел от 10 до 20? - person dannio; 17.08.2015
comment
@dannio Нет, есть условие для $tens - person Rufus L; 14.11.2019

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

    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();
person Shahzad Qureshi    schedule 23.10.2013
comment
Наверное, самый изящный ответ здесь. - person Matt Mitchell; 24.10.2013
comment
Я думаю это самый чистый способ сделать это - person Serj Sagan; 30.04.2014
comment
Несомненно лучший ответ. На самом деле это полагается на число как на текст, а не на сложную математическую формулу. Именно так бы это понял сам человеческий мозг, и это идеально. - person Chris Pratt; 12.09.2014
comment
Это хороший ответ, но если метод называется DisplayWithSuffix, то возвращаемый ответ должен включать число, чтобы 1 возвращал 1-й, а не только st. - person HitLikeAHammer; 22.10.2014
comment
Хорошее замечание, HitLikeAHammer. Я настрою код, чтобы отразить это. - person Shahzad Qureshi; 27.10.2014
comment
Вероятно, вы захотите поместить num.ToString() в переменную. Не уверен, что кто-то посчитал бы этот ответ простым, понятным или быстрым, если честно. - person Rudey; 08.12.2018
comment
@ Руди Точно, -1. - person Ondrej Tucny; 13.11.2019

@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);
}
person Scott Dorman    schedule 16.09.2008
comment
Ха, спасибо, вот-вот отправлю код, который я написал. Думаю, ваш в любом случае превосходит мой с битом String.Format. - person Matt Mitchell; 16.09.2008
comment
1) Почему перевод в десятичный? Простой (number / 10) % 10 делает свое дело. 2) Почему вы инициализируете suffix значением, которое никогда не будет использоваться? - person CodesInChaos; 06.06.2014
comment
@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' случайных ошибок. - person Scott Dorman; 06.06.2014
comment
@ScottDorman 1) Только если вы оставите вызов Floor, что бессмысленно для целых чисел. Целочисленное деление просто обрезается до нуля, нет необходимости приводить к десятичному виду или использовать Floor. (number / 10) % 10 проще и работает. 2) Эти ошибки возникают, если вы пропустили путь кода. Ошибка компилятора говорит вам исправить эту ошибку вместо того, чтобы молча возвращать бесполезное значение. - person CodesInChaos; 06.06.2014

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

    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, просто удалите это ключевое слово

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

person mjallday    schedule 16.09.2008
comment
Не работает. 1011% 10 == 1. 1011-е неверно. - person Matt Mitchell; 16.09.2008
comment
Мне нравится, как вы объявляете переменную one и никогда ее не используете. - person John Gietzen; 09.05.2009
comment
@MattMitchell В вашем примере это будет 10110-й, а не 1011-й - person eoleary; 30.04.2013
comment
@EOLeary не уверен, что вы говорите, но я думаю, что редактирование Маршалла послужило моему примеру. - person Matt Mitchell; 30.04.2013
comment
Зачем использовать float вместо простых целых чисел? Я бы использовал (number / 10) % 10. - person CodesInChaos; 06.06.2014
comment
Нет необходимости использовать Math.Floor; деление отбрасывает десятичные дроби, пока оба числа равны int. Следует читать как var tens = number / 10 % 10; - person Pluto; 30.10.2019

Вот версия функции 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
person redcalx    schedule 04.03.2009
comment
Я только что написал эту функцию почти дословно! Различия: master db, cast вместо convert, и я использую немного другой отступ. Думаю, великие умы ... - person John Gietzen; 09.05.2009
comment
+1 - Просто была потребность в версии SQL - спасло меня, написав одну - person HeavenCore; 26.04.2012
comment
Превосходно, но только если мы получаем данные из SQL. Но в этом случае я форматирую переменную DateTime .net. Но эта функция будет безмерно полезной. - person santubangalore; 27.06.2014

Я знаю, что это не ответ на вопрос 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?

person avenmore    schedule 15.02.2012

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

/// <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";
            }
        }
    }
}
person Frank Hoffman    schedule 12.12.2013
comment
Собственно хороший ответ. Но он общий, то есть не относится к датам месяца. Я имел в виду только свидания. Таким образом, значение выше 100 может быть неприменимо. - person santubangalore; 27.06.2014

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

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

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

person Hugh Buchanan    schedule 16.09.2008
comment
Учитывая все строки локализации валюты и т. Д., Добавление порядкового суффикса кажется немного натянутым. - person Matt Mitchell; 16.09.2008

person    schedule
comment
давай. что ты пишешь? Это не имеет ничего общего с моим вопросом. - person santubangalore; 27.06.2014