在c#中有创建序数的简单方法吗?

时间:2022-03-09 16:07:07

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

c#中是否有一种简单的方法来为数字创建序数?例如:

  • 1 returns 1st
  • 1返回1
  • 2 returns 2nd
  • 2返回2
  • 3 returns 3rd
  • 3返回第三
  • ...etc

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

可以通过String.Format()实现此操作吗?还是有任何函数可以实现此操作?

17 个解决方案

#1


272  

This page gives you a complete listing of all custom numerical formatting rules:

此页面提供了所有自定义数值格式规则的完整列表:

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

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

As you can see, there is nothing in there about ordinals, so it can't be done using String.Format. However its not really that hard to write a function to do it.

正如您所看到的,关于序号没有任何内容,因此不能使用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";
    }

}

Update: Technically Ordinals don't exist for <= 0, so I've updated the code above. Also removed the redundant ToString() methods.

更新:从技术上讲,<= 0不存在序号,所以我更新了上面的代码。还删除了冗余ToString()方法。

Also note, this is not internationalised. I've no idea what ordinals look like in other languages.

还需要注意的是,这不是国际化的。我不知道其他语言中的序数是什么样子。

#2


69  

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!

例如,在西班牙语中,“1”被写成“1”。o”、“1。”、“1。操作系统”或“1。比如“取决于你数的是阳性的,阴性的还是复数的!”

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

因此,如果您的软件需要支持不同的语言,尽量避免使用序号。

#3


19  

My version of Jesse's version of Stu's and samjudson's versions :)

我的版本是杰西版本的斯图和森贾德森版本:)

Included unit test to show that the accepted answer is incorrect when number < 1

包含单元测试,以显示当数字< 1时,所接受的答案是不正确的

    /// <summary>
    /// Get the ordinal value of positive integers.
    /// </summary>
    /// <remarks>
    /// Only works for english-based cultures.
    /// Code from: http://*.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());
    }

#4


13  

You'll have to roll your own. From the top of my head:

你得自己动手。从我的头顶:

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

You can then do

你可以做

Console.WriteLine(432.Ordinal());

Edited for 11/12/13 exceptions. I DID say from the top of my head :-)

编辑11/12/13例外。我从我的头顶上说:-)

Edited for 1011 -- others have fixed this already, just want to make sure others don't grab this incorrect version.

为1011编辑——其他人已经修复了这个,只是想确保其他人不会抓取这个错误的版本。

#5


12  

I rather liked elements from both Stu's and samjudson's solutions and worked them together into what I think is a usable combo:

我相当喜欢斯图和萨姆贾德森的解决方案中的元素,并将它们结合在一起,我认为这是一个有用的组合:

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

#6


11  

Simple, clean, quick

简单,干净,快速

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

Or better yet, as an extension method

或者更好,作为一种扩展方法

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

Now you can just call

现在你可以打电话了

int a = 1;
a.DisplayWithSuffix(); 

or even as direct as

甚至是直接的

1.DisplayWithSuffix();

#7


8  

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:

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

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.

注意,如果在紧密循环中生成大量序数,那么条件的减少和数组查找的使用应该会提高性能。然而,我也承认这并不像case语句解决方案那样具有可读性。

#8


3  

Similar to Ryan's solution, but even more basic, I just use a plain array and use the day to look up the correct ordinal:

与Ryan的解决方案类似,但更基本的是,我只是使用一个简单的数组,并利用这一天来查找正确的序号:

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

I have not had the need, but I would assume you could use a multidimensional array if you wanted to have multiple language support.

我还没有这个需求,但是如果您想要有多语言支持,我假设您可以使用多维数组。

From what I can remember from my Uni days, this method requires minimal effort from the server.

从我在大学时的记忆中,这个方法只需要很少的服务器工作。

#9


3  

    private string getOrd(int num)
    {
        return $"{num}{(Range(11,3).Any(n => n == num % 100) ^ Range(1, 3).All(n => n != num%10) ? "th" : new[] { "st", "nd", "rd" }[num % 10-1])}";
    }

If anyone looking for one liner :p

如果有人想找一句:p

#10


2  

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

#11


1  

FWIW, for MS-SQL, this expression will do the job. Keep the first WHEN (WHEN num % 100 IN (11, 12, 13) THEN 'th') as the first one in the list, as this relies upon being tried before the others.

对于MS-SQL, FWIW可以使用这个表达式。将第一个WHEN (num % 100 IN(11,12,13)然后'th')保留为列表中的第一个WHEN(当num % 100 IN(然后'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

For Excel :

擅长:

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

The expression (MOD(A1-11,100)>2) is TRUE (1) for all numbers except any ending in 11,12,13 (FALSE = 0). So 2 * RIGHT(A1) * (MOD(A1-11,100)>2) +1) ends up as 1 for 11/12/13, otherwise :
1 evaluates to 3
2 to 5,
3 to 7
others : 9
- and the required 2 characters are selected from "thstndrdth" starting from that position.

表达式(MOD(A1 - 11100)> 2)是正确的(1)所有数据除了任何结束在11日12日13日(假= 0)。所以2 *(A1)*(MOD(A1 - 11100)> 2)+ 1)最终作为11/12/13 1,否则:1等于3 2 5 3 - 7人:9 -和所需的2字符选择从“thstndrdth”从这个位置开始。

If you really want to convert that fairly directly to SQL, this worked for me for a handful of test values :

如果您真的想直接将它转换为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
                )

#12


1  

EDIT: As YM_Industries points out in the comment, samjudson's answer DOES work for numbers over 1000, nickf's comment seems to have gone, and I can't remember what the problem I saw was. Left this answer here for the comparison timings.

编辑:正如YM_Industries在评论中指出的,samjudson的答案确实适用于超过1000人的数据,nickf的评论似乎已经消失了,我不记得我看到了什么问题。把这个答案留给比较时间。

An awful lot of these don't work for numbers > 999, as nickf pointed out in a comment (EDIT: now missing).

正如nickf在评论中指出的(编辑:现在消失了),很多这样的数字对>999起不到作用。

Here is a version based off a modified version of samjudson's accepted answer that does.

这里有一个版本是基于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;
}

Also Shahzad Qureshi's answer using string manipulation works fine, however it does have a performance penalty. For generating a lot of these, a LINQPad example program makes the string version 6-7 times slower than this integer one (although you'd have to be generating a lot to notice).

同样地,Shahzad Qureshi使用字符串操作的答案是有效的,但是它确实有性能损失。要生成很多这样的程序,LINQPad示例程序会使字符串版本比这个整数版本慢6-7倍(尽管您需要生成很多这样的程序)。

LINQPad example:

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

#13


1  

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

请求“减少冗余”版本的samjudson的答案…

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

#14


0  

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

#15


0  

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

#16


-2  

Here is the DateTime Extension class. Copy, Paste & Enjoy

这里是DateTime扩展类。复制,粘贴和享受

public static class DateTimeExtensions {

公共静态类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;
    }
}

Result :

结果:

9th October 2014

2014年10月9日

#17


-4  

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

#1


272  

This page gives you a complete listing of all custom numerical formatting rules:

此页面提供了所有自定义数值格式规则的完整列表:

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

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

As you can see, there is nothing in there about ordinals, so it can't be done using String.Format. However its not really that hard to write a function to do it.

正如您所看到的,关于序号没有任何内容,因此不能使用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";
    }

}

Update: Technically Ordinals don't exist for <= 0, so I've updated the code above. Also removed the redundant ToString() methods.

更新:从技术上讲,<= 0不存在序号,所以我更新了上面的代码。还删除了冗余ToString()方法。

Also note, this is not internationalised. I've no idea what ordinals look like in other languages.

还需要注意的是,这不是国际化的。我不知道其他语言中的序数是什么样子。

#2


69  

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!

例如,在西班牙语中,“1”被写成“1”。o”、“1。”、“1。操作系统”或“1。比如“取决于你数的是阳性的,阴性的还是复数的!”

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

因此,如果您的软件需要支持不同的语言,尽量避免使用序号。

#3


19  

My version of Jesse's version of Stu's and samjudson's versions :)

我的版本是杰西版本的斯图和森贾德森版本:)

Included unit test to show that the accepted answer is incorrect when number < 1

包含单元测试,以显示当数字< 1时,所接受的答案是不正确的

    /// <summary>
    /// Get the ordinal value of positive integers.
    /// </summary>
    /// <remarks>
    /// Only works for english-based cultures.
    /// Code from: http://*.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());
    }

#4


13  

You'll have to roll your own. From the top of my head:

你得自己动手。从我的头顶:

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

You can then do

你可以做

Console.WriteLine(432.Ordinal());

Edited for 11/12/13 exceptions. I DID say from the top of my head :-)

编辑11/12/13例外。我从我的头顶上说:-)

Edited for 1011 -- others have fixed this already, just want to make sure others don't grab this incorrect version.

为1011编辑——其他人已经修复了这个,只是想确保其他人不会抓取这个错误的版本。

#5


12  

I rather liked elements from both Stu's and samjudson's solutions and worked them together into what I think is a usable combo:

我相当喜欢斯图和萨姆贾德森的解决方案中的元素,并将它们结合在一起,我认为这是一个有用的组合:

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

#6


11  

Simple, clean, quick

简单,干净,快速

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

Or better yet, as an extension method

或者更好,作为一种扩展方法

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

Now you can just call

现在你可以打电话了

int a = 1;
a.DisplayWithSuffix(); 

or even as direct as

甚至是直接的

1.DisplayWithSuffix();

#7


8  

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:

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

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.

注意,如果在紧密循环中生成大量序数,那么条件的减少和数组查找的使用应该会提高性能。然而,我也承认这并不像case语句解决方案那样具有可读性。

#8


3  

Similar to Ryan's solution, but even more basic, I just use a plain array and use the day to look up the correct ordinal:

与Ryan的解决方案类似,但更基本的是,我只是使用一个简单的数组,并利用这一天来查找正确的序号:

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

I have not had the need, but I would assume you could use a multidimensional array if you wanted to have multiple language support.

我还没有这个需求,但是如果您想要有多语言支持,我假设您可以使用多维数组。

From what I can remember from my Uni days, this method requires minimal effort from the server.

从我在大学时的记忆中,这个方法只需要很少的服务器工作。

#9


3  

    private string getOrd(int num)
    {
        return $"{num}{(Range(11,3).Any(n => n == num % 100) ^ Range(1, 3).All(n => n != num%10) ? "th" : new[] { "st", "nd", "rd" }[num % 10-1])}";
    }

If anyone looking for one liner :p

如果有人想找一句:p

#10


2  

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

#11


1  

FWIW, for MS-SQL, this expression will do the job. Keep the first WHEN (WHEN num % 100 IN (11, 12, 13) THEN 'th') as the first one in the list, as this relies upon being tried before the others.

对于MS-SQL, FWIW可以使用这个表达式。将第一个WHEN (num % 100 IN(11,12,13)然后'th')保留为列表中的第一个WHEN(当num % 100 IN(然后'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

For Excel :

擅长:

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

The expression (MOD(A1-11,100)>2) is TRUE (1) for all numbers except any ending in 11,12,13 (FALSE = 0). So 2 * RIGHT(A1) * (MOD(A1-11,100)>2) +1) ends up as 1 for 11/12/13, otherwise :
1 evaluates to 3
2 to 5,
3 to 7
others : 9
- and the required 2 characters are selected from "thstndrdth" starting from that position.

表达式(MOD(A1 - 11100)> 2)是正确的(1)所有数据除了任何结束在11日12日13日(假= 0)。所以2 *(A1)*(MOD(A1 - 11100)> 2)+ 1)最终作为11/12/13 1,否则:1等于3 2 5 3 - 7人:9 -和所需的2字符选择从“thstndrdth”从这个位置开始。

If you really want to convert that fairly directly to SQL, this worked for me for a handful of test values :

如果您真的想直接将它转换为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
                )

#12


1  

EDIT: As YM_Industries points out in the comment, samjudson's answer DOES work for numbers over 1000, nickf's comment seems to have gone, and I can't remember what the problem I saw was. Left this answer here for the comparison timings.

编辑:正如YM_Industries在评论中指出的,samjudson的答案确实适用于超过1000人的数据,nickf的评论似乎已经消失了,我不记得我看到了什么问题。把这个答案留给比较时间。

An awful lot of these don't work for numbers > 999, as nickf pointed out in a comment (EDIT: now missing).

正如nickf在评论中指出的(编辑:现在消失了),很多这样的数字对>999起不到作用。

Here is a version based off a modified version of samjudson's accepted answer that does.

这里有一个版本是基于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;
}

Also Shahzad Qureshi's answer using string manipulation works fine, however it does have a performance penalty. For generating a lot of these, a LINQPad example program makes the string version 6-7 times slower than this integer one (although you'd have to be generating a lot to notice).

同样地,Shahzad Qureshi使用字符串操作的答案是有效的,但是它确实有性能损失。要生成很多这样的程序,LINQPad示例程序会使字符串版本比这个整数版本慢6-7倍(尽管您需要生成很多这样的程序)。

LINQPad example:

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

#13


1  

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

请求“减少冗余”版本的samjudson的答案…

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

#14


0  

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

#15


0  

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

#16


-2  

Here is the DateTime Extension class. Copy, Paste & Enjoy

这里是DateTime扩展类。复制,粘贴和享受

public static class DateTimeExtensions {

公共静态类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;
    }
}

Result :

结果:

9th October 2014

2014年10月9日

#17


-4  

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