C #에서 서수를 만드는 쉬운 방법이 있습니까?


202

C #에서 숫자에 대한 서수 를 만드는 쉬운 방법이 있습니까? 예를 들면 다음과 같습니다.

  • 1은 1을 반환
  • 2는 2를 반환
  • 3은 3을 반환
  • ...기타

이 작업을 수행 할 수 있습니까 String.Format()? 아니면이를 수행 할 수있는 기능이 있습니까?

답변:


310

이 페이지는 모든 사용자 지정 숫자 서식 규칙의 전체 목록을 제공합니다.

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()방법 도 제거했습니다 .

또한 국제화되지 않았습니다. 나는 다른 언어에서 서 수가 어떻게 생겼는지 전혀 모른다.


2
Assert.AreEqual ( "0", AddOrdinal (0)); wisegeek.com/what-is-an-ordinal-number.htm
si618

2
확장 방법 (또는 그것이 무엇이든-@ Stu의 답변 참조)을 사용하면 여기서 잘 작동합니다. @Si, 필요한 경우 해당 조건을 추가하는 것은 매우 쉽습니다.
strager

12
'11 일, 12 일 13 일 '을 잊어 버렸습니다 ... 인터뷰 질문이어야합니다. :-)
Holf

2
그래, 프로그래머는 이상하다;)
samjudson

2
@IanWarburton 단일 리턴 문 만 적중되므로 중복성이 없습니다. 답변이 마음에 들지 않으면, "적절한"방법을 제시하고 그 이유가 무엇인지 알려주십시오.
B2K

73

국제화를 기억하십시오!

이 솔루션은 영어로만 작동합니다. 다른 언어를 지원해야 할 경우 상황이 훨씬 복잡해집니다.

예를 들어 스페인어에서 "1st"는 세는 것이 남성적이든 여성적이든 복수형인지에 따라 "1.o", "1.a", "1.os"또는 "1.as"로 작성됩니다. !

따라서 소프트웨어가 다른 언어를 지원해야하는 경우 서수를 피하십시오.


7
@ Andomar : "처음 2 독자"=> 이탈리아어 (그리고 스페인어도) "처음"은 복수입니다. 따라서 당신은 단수 남성, 단수 여성, 복수 남성, 복수 여성이 있습니다. 어쩌면 어떤 언어는 중립적 인 경우도 있습니다 (남자 / 동물과 구별)
M.Turrini

2
즉, 서수를 피할 필요가 없습니다. 직면 할 수있는 모든 사례를 알고 있거나 (고객이) 일부 제한 사항을 수락하면 현지화에 서수를 포함 시키십시오.
M.Turrini

26
.NET 팀이 DateTime 포맷터에 추가하지 않도록 조정 한 이유를 설명합니다.
Chris S

moment.js는 로케일에 의해 "기본"형식화 기능을 가지고 있기 때문에 가능한 것처럼 보입니다. 또한 DateTime을 위해 .NET에서 수행했으면 좋겠습니다.
Guillaume86

5
모두 "."를 사용하면 매우 간단합니다. 우리가 독일어로하는 서수를위한 문자)))) 1. 1. 2. 3. 4. 5. 등. 비록 숫자를 써서 4에서 변곡점을 추가해야한다면 알고리즘은 훨씬 더 흥미로울 것입니다. 12 가지 다른 조합의 단수 및 복수의 경우 외에 3 개의 다른 기사를 가진 문법적 경우. 그것을 생각하러 오십시오, 러시아 사람들은 2 더하고 vocativ를 가지고 있지 않으며 일부 북유럽 언어는 15를 가지고 있습니다. .NET에서 해당 구현을보고 싶었습니다.
Stefan Steiger

22

Jesse 버전의 Stu 및 samjudson 버전 :)

숫자 <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());
    }

15

간단하고 깨끗하며 빠릅니다.

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

14

당신은 자신의 롤을해야합니다. 내 머리 꼭대기에서 :

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로 편집 됨-다른 사람들은 이미이 문제를 해결했습니다. 다른 사람들 이이 잘못된 버전을 잡지 않도록하십시오.


12

나는 Stusamjudson 의 솔루션 모두에서 요소를 좋아 했으며 사용 가능한 콤보라고 생각하는 요소로 함께 작동했습니다.

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

1
"th"에 상수를 사용하는 이유는 무엇입니까?
nickf

코드에서 두 번 사용되기 때문입니다. 반복하지 말아야 할 오래된 지혜를 활용하기 만하면됩니다.이 경우, .NET 런타임은 코드에 두 개의 "th"가있는 문자열의 복사본 하나만 생성해야합니다. 두 개의 문자열이 생성됩니다. 메모리에서 참조됩니다.
Jesse C. Slicer

25
또한 TH의 값이 변경되면 설정됩니다.
Eclipse

7
@Jesse - 당신은 내 +1 얻을,하지만 난 볼, 손잡이 끈이 방법을 .NET을 믿지 않는 yoda.arachsys.com/csharp/strings.html#interning 그 내 독서는 "일"문자에 대한 각 참조입니다, 동일한 메모리 비트를 참조합니다. 그러나 나는 DRY에 동의합니다 :)
si618

4
이와 같은 중복을 제거하면 가독성이 저하되므로 혼동이 "왜 TH인가?"라고 생각합니다. DRY가 '비용에 관계없이 모든 중복 제거'로 해석되어서는 안된다고 생각합니다.
SeeNoWeevil

8

아직 벤치마킹하지는 않았지만 모든 조건부 사례를 피함으로써 더 나은 성능을 얻을 수 있어야합니다.

이것은 자바이지만 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();
  }
}

엄격한 루프에서 많은 서수를 생성하는 경우 조건부 감소 및 배열 조회를 사용하면 성능이 향상됩니다. 그러나 나는 이것이 case statement 솔루션만큼 읽을 수 없다는 것을 인정합니다.


C #에서 이것을 벤치마킹하여 죄송합니다. 버전이 si618의 솔루션보다 빠르지 않습니다.
GY_

이 답변을 확인하십시오. stackoverflow.com/a/58378465/2583579
Dan Dohotaru

3

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

필요하지는 않았지만 여러 언어 지원을 원한다면 다차원 배열을 사용할 수 있다고 가정합니다.

Uni 시절부터 기억할 수있는 것으로부터이 방법은 서버의 노력이 거의 필요하지 않습니다.


2

이 확장 클래스를 사용합니다.

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

11 일, 12 일, 13 일
Kcoder

2

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

2
"GetIndicator"를 a public static로 표시하고보다 니모닉 이름 (예 : "OrdinalSuffix")으로 이름을 바꿉니다. 발신자는 다른 형식 (예 : 쉼표)으로 숫자 부분을 원할 수 있습니다.
Tom

2
        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] : "ᵗʰ")}";

누군가 하나의 라이너를 찾고 있다면 : p


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

1

편집 : YM_Industries가 의견에서 지적한 것처럼 samjudson의 답변 은 1000 개가 넘는 숫자에서 작동하지만 nickf의 의견은 사라진 것 같습니다. 그리고 내가 본 문제가 무엇인지 기억할 수 없습니다. 비교 타이밍을 위해이 답변을 여기에 남겨 두십시오.

이들의 끔찍한 많은으로, 숫자> 999 일을하지 않는 nickf이 코멘트 (지금 실종 EDIT)에서 지적했다.

다음은 수정 된 버전의 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";
        }
}

@nickf의 의견을 찾을 수 없습니다. samjudson의 답변에 어떤 문제가 있습니까? 1000보다 큰 숫자를 처리하는 것보다 훨씬 잘 읽을 수있는 것처럼 보입니다.
Joshua Walsh

1
공정한 의견입니다. 방금 테스트 세트를 실행했는데 문제를 찾을 수 없습니다. Sam의 답변에 대한 수정 사항이 없었기 때문에 내가 화가 났을 때만 상상할 수 있습니다. 이를 반영하기 위해 답변을 편집했습니다.
Whelkaholism

1
하하, 우리 모두 그렇지 않은 순간이 있습니까? 우리는 예전의 코드를 되돌아 보면서 "도대체 왜 이것을 작성 했습니까?"
Joshua Walsh

1

다른 답변을 기반으로 :

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

3
첫 번째 장소 : 가장 불필요하게 암호화 된 답변. "불필요하게": 가독성 비용이 들지 않는 코드 크기 / 성능 이점. "Cryptic": "법인"요구 사항에 매핑하기 위해 상당한 번역이 필요했습니다.
Tom

0

FWIW, MS-SQL의 경우이식이 작업을 수행합니다. 첫 번째 WHEN ( 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)

(FALSE = 0)으로 (MOD(A1-11,100)>2)끝나는 것을 제외한 모든 숫자에 대해 표현식 은 TRUE (1)입니다 11,12,13. 그래서 2 * RIGHT(A1) * (MOD(A1-11,100)>2) +1)그렇지 않으면 11/12/13 1로 끝나는 :
1 ~ 3로 평가
5-2,
3 ~ 7
기타 : 9
-와가에서 선택되는 2 개 문자 필요한 "thstndrdth"그 위치에서 시작.

이것을 상당히 직접 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
                )

0

이것은 구현이며 dart언어에 따라 수정 될 수 있습니다.

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

0

여기에는 좋은 대답이 많이 있지만 다른 것에 대한 여지가 있다고 생각합니다. 이번에는 패턴 일치를 기반으로합니다. 다른 것이 아니라면 적어도 논쟁의 여지가 있습니다.

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

이 솔루션이 특별한 이유는 무엇입니까? 다른 다양한 솔루션에 대한 성능 고려 사항을 추가하고 있다는 사실 만

솔직히 나는이 특정 시나리오 (실제로 수백만의 서 수가 필요한)에 대해 성능이 중요하다고 의심하지만 적어도 비교를 고려해야 할 부분이 있습니다 ...

참조를위한 100 만 항목 (밀링은 기계 사양에 따라 다를 수 있음)

패턴 일치 및 나누기 (이 답변)

~ 622ms

패턴 일치 및 문자열 (이 답변)

~ 1967ms

두 개의 스위치와 구분 (허용 된 답변)

~ 637ms

하나의 스위치와 부서로 (또 다른 대답)

~ 725ms

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

0

또 다른 one-liner이지만 정규 표현식 결과를 배열로만 색인화하여 비교하지 않습니다.

public static string GetOrdinalSuffix(int input)
{
    return new []{"th", "st", "nd", "rd"}[Convert.ToInt32("0" + Regex.Match(input.ToString(), "(?<!1)[1-3]$").Value)];
}

PowerShell 버전을 더 단축 할 수 있습니다.

function ord($num) { return ('th','st','nd','rd')[[int]($num -match '(?<!1)[1-3]$') * $matches[0]] }

0

다른 1 개의 강선.

public static string Ordinal(this int n)
{    
 return n + (new [] {"st","nd","rd" }.ElementAtOrDefault((((n + 90) % 100 - 10) % 10 - 1)) ?? "th");
}

-2

다음은 DateTime Extension 클래스입니다. 복사, 붙여 넣기 및 즐기기

공개 정적 클래스 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 일


a) 날짜 형식 문자열 (X5) 및 b) 메소드의 전체 나머지 (사용 사례가 발생하지 않았을 경우) 목적 또는 심지어 날짜 형식 문자열이 다른 요일). 내가 제안한 "OrdinalSuffix"방법을 사용하여 Ian Warburton의 4 월 6 일 17시 16 분 32 초 답변 ( stackoverflow.com/questions/20156/… ).
Tom

-3

다른 모든 제안을 기반으로 사용한 다른 대안이지만 특별한 케이스가 필요하지 않습니다.

    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";
        }
    }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.