【问题标题】:Is there an easy way to create ordinals in C#?有没有一种简单的方法可以在 C# 中创建序数?
【发布时间】:2010-09-06 10:00:03
【问题描述】:

在 C# 中是否有一种简单的方法可以为数字创建 Ordinals?例如:

  • 1 返回第一个
  • 2 返回第二个
  • 3 返回第三
  • ...等

这可以通过String.Format() 来完成吗?或者有什么功能可以做到这一点?

【问题讨论】:

    标签: c# .net ordinals


    【解决方案1】:

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

    Custom numeric format strings

    如您所见,其中没有关于序数的任何内容,因此无法使用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";
        }
    }
    

    更新:从技术上讲,ToString() 方法。

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

    【讨论】:

    • Assert.AreEqual("0", AddOrdinal(0));见wisegeek.com/what-is-an-ordinal-number.htm
    • 使用扩展方法(或其他任何方法——见@Stu 的回答)在这里会很好用。 @Si,如果需要,添加该条件将非常容易。
    • 如果我把它作为扩展方法,我会称之为“ToOrdinalString”。
    • 忘记了'11th, 12th 13th'...应该是面试题。 :-)
    • 是的,程序员很奇怪 ;)
    【解决方案2】:

    记住国际化!

    此处的解决方案仅适用于英语。如果您需要支持其他语言,事情会变得更加复杂。

    例如,在西班牙语中,“1st”会写成“1.o”、“1.a”、“1.os”或“1.as”,具体取决于您计算的对象是否为阳性,女性或复数!

    因此,如果您的软件需要支持不同的语言,请尽量避免使用序数。

    【讨论】:

    • @Andomar:“前 2 位读者”=> 意大利语(我想也是西班牙语)“first”在这里是复数形式。所以你有单数阳性,单数阴性,复数阳性,复数阴性;也许某些语言也有中性情况(将事物与人/动物区分开来)
    • 也就是说,您不必避免使用序数:将它们包含在本地化中,一旦您知道您可能面临的所有情况,或者(让您的客户)接受一些限制。
    • 这解释了为什么 .NET 团队避免将其添加到 DateTime 格式化程序中
    • moment.js 有一个按区域设置的“序数”格式化功能,所以它看起来是可行的,也希望他们能在 .NET 中为 DateTime 完成它
    • 如果你们都用“.”就很简单了。序数的字符,就像我们在德语中所做的那样语法格有3个不同的冠词,此外还有12个不同组合的单数格和复数格。想想看,我认为俄罗斯人不是还有 2 个,加上 vocativ,而一些北欧语言有 15 个。我很想在 .NET 中看到这种实现。
    【解决方案3】:

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

    包含单元测试以显示当数字

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

    【讨论】:

      【解决方案4】:

      简单、干净、快速

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

      【讨论】:

        【解决方案5】:

        你必须自己动手。从我的头顶:

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

        针对 2013 年 11 月 12 日的例外情况进行了编辑。我确实是从头顶上说的:-)

        为 1011 编辑过——其他人已经修复了这个问题,只是想确保其他人不会抓住这个不正确的版本。

        【讨论】:

          【解决方案6】:

          我更喜欢 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;
              }
          }
          

          【讨论】:

          • 对“th”使用常量的原因是什么?
          • 因为它在代码中被使用了两次。只是利用你不应该重复自己的古老智慧:) 在这种情况下,.NET 运行时应该只创建字符串的一个副本,而在代码中有两个“th”,就会创建两个字符串并在内存中引用。
          • 而且,如果 TH 的值发生变化,您将被设置。
          • @Jesse - 你得到了我的 +1,但我不相信 .NET 以这种方式处理字符串,请参阅 yoda.arachsys.com/csharp/strings.html#interning,我对此的解读是对“th”文字的每个引用都会引用相同的记忆。但我同意 DRY :)
          • 删除这样的重复只会妨碍我认为的可读性,因此会混淆“为什么是 TH?”。我不认为 DRY 应该被解释为“不惜一切代价删除所有重复”。
          【解决方案7】:

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

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

          请注意,如果在紧密循环中生成大量序数,则减少条件和使用数组查找应该会提高性能。但是,我也承认这不如 case 语句解决方案具有可读性。

          【讨论】:

          • 对不起,我在 C# 中对此进行了基准测试,您的版本并不比 si618 的解决方案快。
          • 检查这个答案stackoverflow.com/a/58378465/2583579 以获得一些基准
          【解决方案8】:

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

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

          我没有这个需要,但如果你想支持多语言,我会假设你可以使用多维数组。

          从我大学时代的记忆来看,这种方法只需要很少的服务器工作。

          【讨论】:

            【解决方案9】:
            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] : "ᵗʰ")}";
            

            如果有人正在寻找单线。

            【讨论】:

            • 感谢 unicode 上标 { "ˢᵗ", "ⁿᵈ", "ʳᵈ", "ᵗʰ" }
            【解决方案10】:

            我使用这个扩展类:

            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 日
            【解决方案11】:

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

            【讨论】:

            • 我会将“GetIndicator”公开为public static,并将其重命名为更易记的名称(即“OrdinalSuffix”)。来电者可能需要不同格式的数字部分(即逗号)。
            【解决方案12】:
            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";
            }
            

            【讨论】:

              【解决方案13】:

              编辑:正如 YM_Industries 在评论中指出的那样,samjudson's answer 确实适用于超过 1000 的数字,nickf 的评论似乎已经消失,我不记得我看到的问题是什么。将此答案留在这里用于比较时间。

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

              这是一个基于 samjudsonaccepted answer 的修改版本的版本。

              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 Qureshianswer 使用字符串操作也可以正常工作,但它确实会降低性能。为了生成很多这些,一个 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 以上的数字,同时比你的更具可读性。
              • 这是一个公平的评论,我刚刚运行了一个测试集,我找不到任何问题。山姆的回答似乎也没有任何编辑,所以我只能想象我快疯了。我已经编辑了我的答案以反映这一点。
              • 哈哈,我们都有这样的时刻,不是吗?我们回顾旧代码,然后问“我到底为什么要写这个?”
              【解决方案14】:

              根据其他答案:

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

              【讨论】:

              • 第一名:最不必要的神秘答案。 “不必要”:代码大小/性能优势不值得可读性成本。 “隐秘”:需要大量翻译才能映射到“外行”要求。
              【解决方案15】:

              虽然这里有很多好的答案,但我想还有一个空间,这一次是基于模式匹配,如果没有其他任何东西,那么至少是有争议的可读性

              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 万件供参考(当然,您的米数可能会因机器规格而异)

              带有模式匹配和分割(这个答案)

              ~622 毫秒

              使用模式匹配和字符串(这个答案)

              ~1967 毫秒

              带有两个开关和分区(接受的答案)

              ~637 毫秒

              一个开关和一个分区(另一个答案)

              ~725 毫秒

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

              【讨论】:

                【解决方案16】:

                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)
                

                表达式(MOD(A1-11,100)&gt;2) 对除以11,12,13 (FALSE = 0) 结尾的所有数字之外的所有数字都是TRUE (1)。所以2 * RIGHT(A1) * (MOD(A1-11,100)&gt;2) +1) 在 2013 年 11 月 12 日结束时为 1,否则:
                1 评估为 3
                2到5,
                3 至 7
                其他:9
                - 并且从该位置开始从"thstndrdth" 中选择所需的2 个字符。

                如果您真的想直接将其转换为 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
                                )
                

                【讨论】:

                • 是的,但问题具体说的是C#。如果您愿意,可以将此问题作为 SQL 问题发布,然后将此答案作为答案发布。如果我们允许其他语言的答案,热门问题很快就会被众多热门语言的答案淹没,从而很难找到所请求语言的有用答案。
                【解决方案17】:

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

                【讨论】:

                • 是的,但问题具体说的是C#。如果您愿意,您可以将此问题作为 Dart 问题发布,然后将此答案作为答案发布。如果我们允许其他语言的答案,热门问题很快就会被众多热门语言的答案淹没,从而很难找到所请求语言的有用答案。
                • 将此飞镖代码移植到 C# 非常容易。不过我同意你的说法
                【解决方案18】:

                另一种单行,但不进行比较,仅将正则表达式结果索引到数组中。

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

                【讨论】:

                  【解决方案19】:

                  另外 1 个班轮。

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

                  【讨论】:

                    【解决方案20】:

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

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

                    结果:

                    2014 年 10 月 9 日

                    【讨论】:

                    • 您正在复制:a) 日期格式字符串 (X5) 和 b) 方法的整个其余部分(当可能的用例出现时(如果尚未出现)序数后缀用于非月份目的,甚至是具有不同日期格式字符串的月份)。使用我建议从 Ian Warburton 的 2017 年 4 月 6 日 16:32 回答 (stackoverflow.com/questions/20156/…) 公开的“OrdinalSuffix”方法。
                    【解决方案21】:

                    我根据所有其他建议使用的另一种替代方法,但不需要特殊的大小写:

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

                    【讨论】:

                      猜你喜欢
                      • 2011-02-16
                      • 2014-01-10
                      • 2012-10-27
                      • 1970-01-01
                      • 1970-01-01
                      • 2023-03-06
                      • 2020-10-18
                      • 2023-03-19
                      相关资源
                      最近更新 更多