Is there an easy way to create ordinals in C#?

2019-01-01 08:18发布

Is there an easy way in C# to create Ordinals for a number? For example:

  • 1 returns 1st
  • 2 returns 2nd
  • 3 returns 3rd
  • ...etc

Can this be done through String.Format() or are there any functions available to do this?

标签: c# .net ordinals
17条回答
流年柔荑漫光年
2楼-- · 2019-01-01 08:39

Remember internationalisation!

The solutions here only work for English. Things get a lot more complex if you need to support other languages.

For example, in Spanish "1st" would be written as "1.o", "1.a", "1.os" or "1.as" depending on whether the thing you're counting is masculine, feminine or plural!

So if your software needs to support different languages, try to avoid ordinals.

查看更多
永恒的永恒
3楼-- · 2019-01-01 08:47

Another alternative that I used based on all the other suggestions, but requires no special casing:

    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";
        }
    }
查看更多
忆尘夕之涩
4楼-- · 2019-01-01 08:49

Requested "less redundancy" version of samjudson's answer...

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);
}
查看更多
明月照影归
5楼-- · 2019-01-01 08:50

Based off the other answers:

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";                                              
}
查看更多
闭嘴吧你
6楼-- · 2019-01-01 08:51

I use this extension class:

public static class Int32Extensions
{
    public static string ToOrdinal(this int i)
    {
        return (i + "th")
            .Replace("1th", "1st")
            .Replace("2th", "2nd")
            .Replace("3th", "3rd");
    }
}
查看更多
明月照影归
7楼-- · 2019-01-01 08:54

While I haven't benchmarked this yet, you should be able to get better performance by avoiding all the conditional case statements.

This is java, but a port to C# is trivial:

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

Note, the reduction of conditionals and the use of the array lookup should speed up performance if generating a lot of ordinals in a tight loop. However, I also concede that this isn't as readable as the case statement solution.

查看更多
登录 后发表回答