Có một cách dễ dàng trong C # để tạo Ordinals đối với một số? Ví dụ:
- 1 trả về 1
- 2 trả về 2
- 3 trả về thứ 3
- ...Vân vân
Điều này có thể được thực hiện thông qua String.Format()
hoặc có bất kỳ chức năng có sẵn để làm điều này?
Có một cách dễ dàng trong C # để tạo Ordinals đối với một số? Ví dụ:
Điều này có thể được thực hiện thông qua String.Format()
hoặc có bất kỳ chức năng có sẵn để làm điều này?
Câu trả lời:
Trang này cung cấp cho bạn một danh sách đầy đủ tất cả các quy tắc định dạng số tùy chỉnh:
http://msdn.microsoft.com/en-us/l Library / 0c899ak8.aspx
Như bạn có thể thấy, không có gì trong đó về các thứ tự, vì vậy không thể thực hiện được bằng String.Format. Tuy nhiên nó không thực sự khó để viết một chức năng để làm điều đó.
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";
}
}
Cập nhật: Về mặt kỹ thuật Thông thường không tồn tại cho <= 0, vì vậy tôi đã cập nhật mã ở trên. Cũng loại bỏ dư thừaToString()
phương pháp .
Cũng lưu ý, điều này không được quốc tế hóa. Tôi không biết thứ tự trông như thế nào trong các ngôn ngữ khác.
Nhớ quốc tế hóa!
Các giải pháp ở đây chỉ làm việc cho tiếng Anh. Mọi thứ trở nên phức tạp hơn rất nhiều nếu bạn cần hỗ trợ các ngôn ngữ khác.
Ví dụ: trong tiếng Tây Ban Nha "1st" sẽ được viết là "1.o", "1.a", "1.os" hoặc "1.as" tùy thuộc vào việc bạn đang đếm là nam tính, nữ tính hay số nhiều !
Vì vậy, nếu phần mềm của bạn cần hỗ trợ các ngôn ngữ khác nhau, hãy cố gắng tránh các chức năng.
Phiên bản của tôi về phiên bản Jesse và samjudson của Jesse :)
Kiểm tra đơn vị bao gồm để chỉ ra rằng câu trả lời được chấp nhận là không chính xác khi số <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());
}
Đơn giản, sạch sẽ, nhanh chóng
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";
}
Hoặc tốt hơn, như một phương pháp mở rộng
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";
}
}
Bây giờ bạn chỉ có thể gọi
int a = 1;
a.DisplayWithSuffix();
hoặc thậm chí trực tiếp như
1.DisplayWithSuffix();
Bạn sẽ phải tự lăn. Từ đỉnh đầu của tôi:
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;
}
Bạn có thể làm
Console.WriteLine(432.Ordinal());
Đã chỉnh sửa cho 11/12/13 trường hợp ngoại lệ. Tôi nói từ trên đỉnh đầu của tôi :-)
Đã chỉnh sửa cho 1011 - những người khác đã sửa lỗi này rồi, chỉ muốn đảm bảo những người khác không lấy phiên bản không chính xác này.
Tôi thích các yếu tố từ các giải pháp của cả Stu và samjudson và kết hợp chúng với nhau thành những gì tôi nghĩ là một kết hợp có thể sử dụng:
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;
}
}
Mặc dù tôi chưa đạt điểm chuẩn này nhưng bạn sẽ có thể có hiệu suất tốt hơn bằng cách tránh tất cả các báo cáo trường hợp có điều kiện.
Đây là java, nhưng một cổng tới C # là tầm thường:
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();
}
}
Lưu ý, việc giảm các điều kiện và việc sử dụng tra cứu mảng sẽ tăng tốc hiệu suất nếu tạo ra nhiều lệnh trong một vòng lặp chặt chẽ. Tuy nhiên, tôi cũng thừa nhận rằng điều này không dễ đọc như giải pháp tuyên bố trường hợp.
Tương tự như giải pháp của Ryan, nhưng thậm chí còn cơ bản hơn, tôi chỉ sử dụng một mảng đơn giản và sử dụng ngày để tra cứu thứ tự chính xác:
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];
Tôi chưa có nhu cầu, nhưng tôi cho rằng bạn có thể sử dụng một mảng đa chiều nếu bạn muốn có nhiều hỗ trợ ngôn ngữ.
Từ những gì tôi có thể nhớ từ những ngày Uni của mình, phương pháp này đòi hỏi nỗ lực tối thiểu từ máy chủ.
Tôi sử dụng lớp mở rộng này:
public static class Int32Extensions
{
public static string ToOrdinal(this int i)
{
return (i + "th")
.Replace("1th", "1st")
.Replace("2th", "2nd")
.Replace("3th", "3rd");
}
}
Phiên bản "ít dư thừa" được yêu cầu của câu trả lời của 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);
}
public static
và đổi tên nó thành một cái tên dễ nhớ hơn (tức là "OrdinalSuffix"). Người gọi có thể muốn phần số ở các định dạng khác nhau (ví dụ như bằng dấu phẩy).
private static string GetOrd(int num) => $"{num}{(!(Range(11, 3).Any(n => n == num % 100) ^ Range(1, 3).All(n => n != num % 10)) ? new[] { "ˢᵗ", "ⁿᵈ", "ʳᵈ" }[num % 10 - 1] : "ᵗʰ")}";
Nếu bất cứ ai tìm kiếm một lót: p
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";
}
EDIT : Như YM_Industries chỉ ra trong bình luận, câu trả lời của samjudson DOES hoạt động với số lượng trên 1000, bình luận của nickf dường như đã biến mất và tôi không thể nhớ vấn đề mình gặp phải là gì. Để lại câu trả lời này ở đây cho thời gian so sánh.
Rất nhiều trong số này không hoạt động với số> 999, như nickf đã chỉ ra trong một nhận xét (EDIT: hiện đang thiếu).
Dưới đây là một phiên bản dựa trên một phiên bản sửa đổi của samjudson 's câu trả lời được chấp nhận mà không.
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;
}
Ngoài ra câu trả lời của Shahzad Qureshi sử dụng thao tác chuỗi hoạt động tốt, tuy nhiên nó có hình phạt hiệu suất. Để tạo ra nhiều thứ này, một chương trình ví dụ LINQPad làm cho phiên bản chuỗi chậm hơn 6-7 lần so với số nguyên này (mặc dù bạn phải tạo ra nhiều thứ để chú ý).
Ví dụ 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";
}
}
Dựa trên các câu trả lời khác:
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";
}
FWIW, đối với MS-SQL, biểu thức này sẽ thực hiện công việc. Giữ WHEN ( WHEN num % 100 IN (11, 12, 13) THEN 'th'
) đầu tiên là danh sách đầu tiên trong danh sách, vì điều này phụ thuộc vào việc được thử trước các mục khác.
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
Đối với Excel:
=MID("thstndrdth",MIN(9,2*RIGHT(A1)*(MOD(A1-11,100)>2)+1),2)
Biểu thức (MOD(A1-11,100)>2)
là TRUE (1) cho tất cả các số trừ mọi kết thúc bằng 11,12,13
(FALSE = 0). Vì vậy, 2 * RIGHT(A1) * (MOD(A1-11,100)>2) +1)
kết thúc là 1 cho 11/12/13, nếu không:
1 đánh giá thành 3
2 đến 5,
3 đến 7
người khác: 9
- và 2 ký tự bắt buộc được chọn từ "thstndrdth"
bắt đầu từ vị trí đó.
Nếu bạn thực sự muốn chuyển đổi khá trực tiếp sang SQL, thì điều này đã giúp tôi với một số giá trị thử nghiệm:
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
)
Đây là việc thực hiện dart
và có thể được sửa đổi theo ngôn ngữ.
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";
}
Mặc dù có rất nhiều câu trả lời hay ở đây, tôi đoán có chỗ cho một câu trả lời khác, lần này dựa trên kết hợp mẫu, nếu không phải là bất cứ điều gì khác, thì ít nhất là cho khả năng đọc dễ tranh cãi
public static string Ordinals1(this int number)
{
switch (number)
{
case int p when p % 100 == 11:
case int q when q % 100 == 12:
case int r when r % 100 == 13:
return $"{number}th";
case int p when p % 10 == 1:
return $"{number}st";
case int p when p % 10 == 2:
return $"{number}nd";
case int p when p % 10 == 3:
return $"{number}rd";
default:
return $"{number}th";
}
}
và điều gì làm cho giải pháp này đặc biệt? không có gì ngoài thực tế là tôi đang thêm một số cân nhắc về hiệu suất cho các giải pháp khác
thành thật mà nói tôi nghi ngờ hiệu suất thực sự quan trọng đối với kịch bản cụ thể này (người thực sự cần thứ tự hàng triệu số) nhưng ít nhất nó cũng đưa ra một số so sánh cần tính đến ...
1 triệu mặt hàng để tham khảo (khóa học của bạn có thể thay đổi dựa trên thông số kỹ thuật của máy)
với sự phù hợp và phân chia mẫu (câu trả lời này)
~ 622 ms
với khớp mẫu và chuỗi (câu trả lời này)
~ 1967 ms
với hai công tắc và bộ phận (câu trả lời được chấp nhận)
~ 637 ms
với một công tắc và bộ phận (câu trả lời khác)
~ 725 ms
void Main()
{
var timer = new Stopwatch();
var numbers = Enumerable.Range(1, 1000000).ToList();
// 1
timer.Reset();
timer.Start();
var results1 = numbers.Select(p => p.Ordinals1()).ToList();
timer.Stop();
timer.Elapsed.TotalMilliseconds.Dump("with pattern matching and divisions");
// 2
timer.Reset();
timer.Start();
var results2 = numbers.Select(p => p.Ordinals2()).ToList();
timer.Stop();
timer.Elapsed.TotalMilliseconds.Dump("with pattern matching and strings");
// 3
timer.Reset();
timer.Start();
var results3 = numbers.Select(p => p.Ordinals3()).ToList();
timer.Stop();
timer.Elapsed.TotalMilliseconds.Dump("with two switches and divisons");
// 4
timer.Reset();
timer.Start();
var results4 = numbers.Select(p => p.Ordinals4()).ToList();
timer.Stop();
timer.Elapsed.TotalMilliseconds.Dump("with one switche and divisons");
}
public static class Extensions
{
public static string Ordinals1(this int number)
{
switch (number)
{
case int p when p % 100 == 11:
case int q when q % 100 == 12:
case int r when r % 100 == 13:
return $"{number}th";
case int p when p % 10 == 1:
return $"{number}st";
case int p when p % 10 == 2:
return $"{number}nd";
case int p when p % 10 == 3:
return $"{number}rd";
default:
return $"{number}th";
}
}
public static string Ordinals2(this int number)
{
var text = number.ToString();
switch (text)
{
case string p when p.EndsWith("11"):
return $"{number}th";
case string p when p.EndsWith("12"):
return $"{number}th";
case string p when p.EndsWith("13"):
return $"{number}th";
case string p when p.EndsWith("1"):
return $"{number}st";
case string p when p.EndsWith("2"):
return $"{number}nd";
case string p when p.EndsWith("3"):
return $"{number}rd";
default:
return $"{number}th";
}
}
public static string Ordinals3(this int number)
{
switch (number % 100)
{
case 11:
case 12:
case 13:
return $"{number}th";
}
switch (number % 10)
{
case 1:
return $"{number}st";
case 2:
return $"{number}nd";
case 3:
return $"{number}rd";
default:
return $"{number}th";
}
}
public static string Ordinals4(this int number)
{
var ones = number % 10;
var tens = Math.Floor(number / 10f) % 10;
if (tens == 1)
{
return $"{number}th";
}
switch (ones)
{
case 1:
return $"{number}th";
case 2:
return $"{number}nd";
case 3:
return $"{number}rd";
default:
return $"{number}th";
}
}
}
Một lớp lót khác, nhưng không có sự so sánh bằng cách chỉ lập kết quả regex thành một mảng.
public static string GetOrdinalSuffix(int input)
{
return new []{"th", "st", "nd", "rd"}[Convert.ToInt32("0" + Regex.Match(input.ToString(), "(?<!1)[1-3]$").Value)];
}
Phiên bản PowerShell có thể được rút ngắn hơn nữa:
function ord($num) { return ('th','st','nd','rd')[[int]($num -match '(?<!1)[1-3]$') * $matches[0]] }
Đây là lớp Gia hạn DateTime. Sao chép, dán và thưởng thức
lớp tĩnh công khai 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;
}
}
Kết quả :
Ngày 9 tháng 10 năm 2014
Một cách khác mà tôi đã sử dụng dựa trên tất cả các đề xuất khác, nhưng không yêu cầu vỏ đặc biệt:
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";
}
}