有一个简单的方法来创build在C#中的序数?

在C#中有一个简单的方法来创build一个数字的序数? 例如:

  • 1返回1
  • 2返回第二
  • 3返回第三
  • …等等

这可以通过String.Format()来完成,还是有任何可用的function来做到这一点?

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

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()方法。

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

记住国际化!

这里的解决scheme只适用于英语。 如果您需要支持其他语言,情况会变得更加复杂。

例如,在西class牙语中,“1st”将根据您所计算的东西是男性,女性还是复数,写成“1.o”,“1.a”,“1.os”或“1.as” !

所以如果你的软件需要支持不同的语言,尽量避免序号。

我版本的Jesse版本的Stu's和samjudson的版本:)

包括unit testing以显示数字<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()); } 

我更喜欢Stu和samjudson的解决scheme中的元素,并将它们合并到我认为是可用的组合中:

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

你将不得不推出自己的。 从我的头顶上:

 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 – 其他人已经修复了这一点,只是想确保别人不抓住这个不正确的版本。

简单,干净,快捷

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

虽然我还没有对此进行基准testing,但您应该能够通过避免所有的条件语句来获得更好的性能。

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

请注意,条件的减less和数组查询的使用会加速性能,如果在紧密的循环中产生大量的序数。 不过,我也承认,这不像案件陈述的解决scheme那样可读。

类似Ryan的解决scheme,但更基本的,我只是使用一个普通的数组,并使用一天来查找正确的序号:

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

我没有这个需要,但是我会假设你可以使用multidimensional array,如果你想有多种语言的支持。

从我能记得的我的Uni时代,这种方法需要服务器的最小的努力。

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

如果有人在寻找一个class轮:第

我使用这个扩展类:

 public static class Int32Extensions { public static string ToOrdinal(this int i) { return (i + "th") .Replace("1th", "1st") .Replace("2th", "2nd") .Replace("3th", "3rd"); } } 

FWIW,对于MS-SQL,这个expression式可以完成这个工作。 保留第一个时间(当时的WHEN num % 100 IN (11, 12, 13) THEN '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 

对于Excel:

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

对于除11,12,13 (FALSE = 0)之外的所有数字,expression式(MOD(A1-11,100)>2)均为TRUE(1)。 所以2 * RIGHT(A1) * (MOD(A1-11,100)>2) +1)在11/12/13结束为1,否则:
1评价为3
2至5个,
3至7
其他:9
– 从该位置开始的"thstndrdth"中select所需的2个字符。

如果你真的想直接把它转换成SQL,那么这对我来说就是一个testing值:

 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 ) 

编辑 :正如YM_Industries在评论中指出的那样, samjudson的答案对1000以上的数字是有效的,nickf的评论似乎已经消失了,我不记得我看到的问题是什么。 在这里留下这个答案比较时间。

其中很多这些不适用于> 999的数字,正如nickf在评论中指出的那样(编辑:现在失踪)。

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

此外, Shahzad Qureshi使用string处理的答案也可以正常工作,但是它的性能会受到影响。 为了生成很多这样的代码,一个LINQPad示例程序使string版本比这个整数慢6-7倍(尽pipe你必须生成很多注意事项)。

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

要求samjudson的答案“less冗余”版本…

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

根据其他答案:

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

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

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

结果:

2014年10月9日

另一种select,我根据所有其他的build议,但不需要特殊的shell:

  public static string DateSuffix(int day) { Math.DivRem(day, 10, out day); switch (day) { case 1: return "st"; case 2: return "nd"; case 3: return "rd"; default: return "th"; } }