Gibt es eine einfache Möglichkeit, Ordnungszahlen in C # zu erstellen?

Gibt es einen einfachen Weg in C #, Ordnungszahlen für eine Zahl zu erstellen? Beispielsweise:

  • 1 gibt 1 zurück
  • 2 gibt 2 zurück
  • 3 gibt 3. zurück
  • …etc

Kann dies über String.Format() geschehen oder gibt es dafür functionen?

Auf dieser Seite finden Sie eine vollständige Liste aller benutzerdefinierten numerischen Formatierungsregeln:

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

Wie Sie sehen können, gibt es nichts über Ordnungszahlen, so dass es nicht mit String.Format gemacht werden kann. Allerdings ist es nicht wirklich so schwer, eine function dafür zu schreiben.

 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: Technisch Ordnungszahlen existieren nicht für < = 0, daher habe ich den obigen Code aktualisiert. Außerdem wurden die redundanten ToString () - Methoden entfernt.

Beachten Sie auch, dass dies nicht internationalisiert ist. Ich habe keine Ahnung, wie Ordinalzahlen in anderen Sprachen aussehen.

Denken Sie an Internationalisierung!

Die Lösungen hier funktionieren nur für Englisch. Die Dinge werden viel komplexer, wenn Sie andere Sprachen unterstützen müssen.

Zum Beispiel würde in Spanisch “1st” als “1.o”, “1.a”, “1.os” oder “1.as” geschrieben werden, abhängig davon, ob das, was Sie zählen, männlich, weiblich oder plural ist !

Wenn Ihre Software verschiedene Sprachen unterstützen muss, versuchen Sie, Ordnungszahlen zu vermeiden.

Meine Version von Jesses Version von Stus und Samjudsons Versionen 🙂

Enthaltener Komponententest, um zu zeigen, dass die akzeptierte Antwort falsch ist, wenn die Nummer <1 ist

  ///  /// Get the ordinal value of positive integers. ///  ///  /// 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 ///  /// The number. /// Ordinal value of positive integers, or  if less than 1. 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()); } 

Sie müssen selbst rollen. Von ganz oben:

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

Sie können dann tun

 Console.WriteLine(432.Ordinal()); 

Bearbeitet für 11/12/13 Ausnahmen. Ich habe es von ganz oben gesagt 🙂

Bearbeitet für 1011 – andere haben dies bereits behoben, wollen nur sicherstellen, dass andere nicht diese falsche Version greifen.

Ich mochte Elemente sowohl von Stu ‘s als auch von Samjudsons Lösungen und arbeitete sie zusammen in einer, wie ich denke, brauchbaren Kombination:

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

Einfach, sauber, schnell

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

Oder noch besser, als Erweiterungsmethode

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

Jetzt können Sie einfach anrufen

 int a = 1; a.DisplayWithSuffix(); 

oder sogar so direkt wie

 1.DisplayWithSuffix(); 

Obwohl ich dies noch nicht bewertet habe, sollten Sie in der Lage sein, eine bessere performance zu erzielen, indem Sie alle bedingten Fallanweisungen vermeiden.

Das ist Java, aber ein Port zu C # ist 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(); } } 

Beachten Sie, dass die Reduzierung von Bedingungen und die Verwendung der Array-Suche die performance beschleunigen sollten, wenn viele Ordnungszahlen in einer engen Schleife generiert werden. Ich gebe jedoch auch zu, dass dies nicht so gut lesbar ist wie die Case-Statement-Lösung.

Ähnlich wie Ryans Lösung, aber noch grundlegender, verwende ich einfach ein einfaches Array und nutze den Tag, um nach der richtigen Ordnungszahl zu suchen:

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

Ich hatte nicht die Notwendigkeit, aber ich würde annehmen, dass Sie ein mehrdimensionales Array verwenden könnten, wenn Sie mehrere Sprachen unterstützen möchten.

Soweit ich mich an meine Uni-Tage erinnern kann, erfordert diese Methode minimalen Aufwand vom Server.

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

Wenn jemand nach einem Liner sucht: p

Ich benutze diese Erweiterungsklasse:

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

Angeforderte “weniger Redundanz” Version von Samjudsons Antwort …

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

FWIW, für MS-SQL wird dieser Ausdruck die Aufgabe übernehmen. Halte den ersten WANN ( WHEN num % 100 IN (11, 12, 13) THEN 'th' ) als den ersten in der Liste, da dies darauf angewiesen ist, vor den anderen versucht zu werden.

 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 

Für Excel:

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

Der Ausdruck (MOD(A1-11,100)>2) ist TRUE (1) für alle Zahlen mit Ausnahme von 11,12,13 (FALSE = 0). Also 2 * RIGHT(A1) * (MOD(A1-11,100)>2) +1) endet als 1 für 11/12/13, sonst:
1 ergibt 3
2 bis 5,
3 bis 7
andere: 9
– und die erforderlichen 2 Zeichen werden von "thstndrdth" ausgehend von dieser Position ausgewählt.

Wenn Sie das wirklich direkt in SQL konvertieren möchten, funktionierte das für mich für eine Handvoll Testwerte:

 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 ) 

EDIT : Wie YM_Industries in dem Kommentar hervorhebt , scheint Samjudsons Antwort für Zahlen über 1000 zu funktionieren, Nickfs Kommentar scheint weg zu sein, und ich kann mich nicht erinnern, was das Problem war, das ich sah. Habe diese Antwort hier für die Vergleichszeiten hinterlassen.

Eine Menge davon funktioniert nicht für Zahlen> 999, wie nickf in einem Kommentar (EDIT: jetzt fehlt) hervorhebt .

Hier ist eine Version, die auf einer modifizierten Version von Samjudsons akzeptierter Antwort basiert.

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

Auch die Antwort von Shahzad Qureshi , die eine String – Manipulation verwendet, funktioniert gut, hat jedoch eine performanceseinbuße. Um eine Menge davon zu generieren, macht ein LINQPad-Beispielprogramm die String-Version 6-7 mal langsamer als diese ganze Zahl (obwohl Sie eine Menge generieren müssten, um es zu bemerken).

LINQPad Beispiel:

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

Basierend auf den anderen Antworten:

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

Hier ist die DateTime-Erweiterungsklasse. Kopieren, einfügen und genießen

öffentliche statische class 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; } } 

Ergebnis:

9. Oktober 2014

Eine andere Alternative, die ich basierend auf all den anderen Vorschlägen verwendet habe, aber keine spezielle Hülle benötigt:

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