Сведения о вопросе

rjevskii

08:44, 15th August, 2020

Теги

c#   .net   ordinals    

Есть ли простой способ создать ординалы в C#?

Просмотров: 374   Ответов: 8

Есть ли простой способ в C# создать Ординалы для числа? Например:

  • 1 возвращается 1-й
  • 2 возврат 2-й
  • 3 возвращается 3-й ..
  • .
  • и т.д.

Можно ли это сделать через String.Format() или есть какие-либо функции, доступные для этого?



  Сведения об ответе

прога

03:27, 15th August, 2020

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

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().

Также обратите внимание, что это не интернационализировано. Я понятия не имею, как выглядят ординалы в других языках.


  Сведения об ответе

+-*/

04:37, 17th August, 2020

Помните об интернационализации!

Решения здесь работают только для английского языка. Все становится намного сложнее, если вам нужно поддерживать другие языки.

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

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


  Сведения об ответе

PIRLO

11:31, 19th August, 2020

Моя версия версии Джесси версии Стью и версии сэмюсона :)

Включен модульный тест, чтобы показать, что принятый ответ неверен, когда число < 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());
    }


  Сведения об ответе

DAAA

20:36, 5th August, 2020

Тебе придется свернуть свой собственный. С самого верха моей головы:

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 - другие уже исправили это, просто хотят убедиться, что другие не схватят эту неправильную версию.


  Сведения об ответе

ASER

18:58, 20th August, 2020

Мне очень понравились элементы из решений Стью и сэмюсона, и я объединил их в то, что я считаю полезным сочетанием:

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


  Сведения об ответе

$DOLLAR

02:02, 22nd August, 2020

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

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


  Сведения об ответе

LAST

15:02, 4th August, 2020

Хотя я еще не провел сравнительный анализ этого, вы должны быть в состоянии получить лучшую производительность, избегая всех условных операторов case.

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

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


  Сведения об ответе

COOL

09:20, 27th August, 2020

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

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

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

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


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться