在c#中有一个简单的方法来创建一个数字的序数吗?例如:
1返回第1位 2返回第2 3返回第3 等
这是否可以通过String.Format()来完成,或者是否有可用的函数来完成?
在c#中有一个简单的方法来创建一个数字的序数吗?例如:
1返回第1位 2返回第2 3返回第3 等
这是否可以通过String.Format()来完成,或者是否有可用的函数来完成?
当前回答
我使用的另一种替代方法是基于所有其他建议,但不需要特殊的大小写:
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";
}
}
其他回答
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";
}
Humanizer nuget包将为您提供帮助方法。免责声明,我是这个项目的贡献者。
Ordinalize将一个数字转换为一个序数字符串,用于表示在一个有序序列中的位置,例如1st, 2nd, 3rd, 4th:
1.Ordinalize() => "1st"
5.Ordinalize() => "5th"
你也可以对数字字符串调用Ordinalize函数,得到相同的结果:"21".Ordinalize() => "21st"
Ordinalize也支持两种形式的语法性别。 您可以将参数传递给Ordinalize,以指定数字应该以哪种性别输出。 可能的值为GrammaticalGender。男性,GrammaticalGender。女性和语法性别。中性:
// for Brazilian Portuguese locale
1.Ordinalize(GrammaticalGender.Masculine) => "1º"
1.Ordinalize(GrammaticalGender.Feminine) => "1ª"
1.Ordinalize(GrammaticalGender.Neuter) => "1º"
"2".Ordinalize(GrammaticalGender.Masculine) => "2º"
"2".Ordinalize(GrammaticalGender.Feminine) => "2ª"
"2".Ordinalize(GrammaticalGender.Neuter) => "2º"
显然,这只适用于某些文化。对于其他人来说,通过或不通过性别对结果没有任何影响。
此外,Ordinalize支持某些区域性应用的变体,这取决于序数在句子中的位置。 使用参数wordForm来获得一个或另一个结果。取值包括:WordForm。缩写和词形式。 你可以结合wordForm参数和性别参数,但是当它不适用时传入这个参数不会对结果产生任何影响。
// Spanish locale
1.Ordinalize(WordForm.Abbreviation) => "1.er" // As in "Vivo en el 1.er piso"
1.Ordinalize(WordForm.Normal) => "1.º" // As in "He llegado el 1º"
"3".Ordinalize(GrammaticalGender.Feminine, WordForm.Abbreviation) => "3.ª"
"3".Ordinalize(GrammaticalGender.Feminine, WordForm.Normal) => "3.ª"
"3".Ordinalize(GrammaticalGender.Masculine, WordForm.Abbreviation) => "3.er"
"3".Ordinalize(GrammaticalGender.Masculine, WordForm.Normal) => "3.º"
如果您想深入了解,请检查这些测试用例:OrdinalizeTests.cs
c# 8和9中接受的带有开关表达式和模式匹配的答案。
没有不必要的字符串转换或分配。
string.Concat(number, number < 0 ? "" : (number % 100) switch
{
11 or 12 or 13 => "th",
int n => (n % 10) switch
{
1 => "st",
2 => "nd",
3 => "rd",
_ => "th",
}
})
或者是不友好的一句话:
$"{number}{(number < 0 ? "" : (number % 100) switch { 11 or 12 or 13 => "th", int n => (n % 10) switch { 1 => "st", 2 => "nd", 3 => "rd", _ => "th" }})}"
编辑:正如YM_Industries在评论中指出的那样,samjudson的答案确实适用于超过1000的数字,nickf的评论似乎已经消失了,我不记得我看到的问题是什么。留下这个答案在这里比较时间。
正如nickf在评论中指出的(编辑:现在丢失了),很多数字> 999都不起作用。
以下是一个基于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使用字符串操作的回答也很好,但它确实有性能损失。为了生成大量这样的类型,LINQPad示例程序使字符串版本比整数版本慢6-7倍(尽管您必须生成很多才会注意到)。
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";
}
}
你得自己动手了。在我的脑海中:
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编辑-其他人已经修复了这个问题,只是想确保其他人不会抓取这个错误的版本。