【问题标题】:Is there an easy way in .NET to get "st", "nd", "rd" and "th" endings for numbers? [duplicate].NET 中是否有一种简单的方法来获取数字的“st”、“nd”、“rd”和“th”结尾? [复制]
【发布时间】:2008-09-16 03:53:16
【问题描述】:

我想知道 .NET 中是否缺少用于转换以下内容的方法或格式字符串:

   1 to 1st
   2 to 2nd
   3 to 3rd
   4 to 4th
  11 to 11th
 101 to 101st
 111 to 111th

This link 有一个关于编写你自己的函数所涉及的基本原则的坏例子,但我更好奇是否有我缺少的内置容量。

解决方案

Scott Hanselman 的答案是公认的,因为它直接回答了问题。

但是,有关解决方案,请参阅this great answer

【问题讨论】:

标签: .net formatting date ordinals


【解决方案1】:

这是一个比你想象的要简单得多的函数。尽管为此可能已经存在一个 .NET 函数,但以下函数(用 PHP 编写)可以完成这项工作。移植它应该不会太难。

function ordinal($num) {
    $ones = $num % 10;
    $tens = floor($num / 10) % 10;
    if ($tens == 1) {
        $suff = "th";
    } else {
        switch ($ones) {
            case 1 : $suff = "st"; break;
            case 2 : $suff = "nd"; break;
            case 3 : $suff = "rd"; break;
            default : $suff = "th";
        }
    }
    return $num . $suff;
}

【讨论】:

  • 本地化怎么样?
  • 本地化意味着您必须为每种语言创建单独的函数。在德语中,您可以只附加“ter”,但“1ter”“2ter”“3ter”看起来非常糟糕,即使它在语法上是正确的。在法语中,它会好一点,但没有适用于每种语言的通用方式。
  • @MichaelStum:实际上在德语中你不能只添加“ter”。考虑“Heute ist der 1te Januar”(今天是 1 月 1 日)。或“Klicken Sie den 5ten Button”(单击第 5 个按钮)。仅举几十个案例中的两个。您必须为每次使用考虑适当的屈曲(英语屈折)。
  • 将数字和这样的后缀组合在德语中是不常见的。你要么写成“1”。或“erster”/“erste”。后者一般用的是文本,很少需要自动生成。
  • @dannio 不,$tens 有一个条件
【解决方案2】:

简单、干净、快速

    private static string GetOrdinalSuffix(int num)
    {
        string number = num.ToString();
        if (number.EndsWith("11")) return "th";
        if (number.EndsWith("12")) return "th";
        if (number.EndsWith("13")) return "th";
        if (number.EndsWith("1")) return "st";
        if (number.EndsWith("2")) return "nd";
        if (number.EndsWith("3")) return "rd";
        return "th";
    }

或者更好,作为一种扩展方法

public static class IntegerExtensions
{
    public static string DisplayWithSuffix(this int num)
    {
        string number = num.ToString();
        if (number.EndsWith("11")) return number + "th";
        if (number.EndsWith("12")) return number + "th";
        if (number.EndsWith("13")) return number + "th";
        if (number.EndsWith("1")) return number + "st";
        if (number.EndsWith("2")) return number + "nd";
        if (number.EndsWith("3")) return number + "rd";
        return number + "th";
    }
}

现在你可以打电话了

int a = 1;
a.DisplayWithSuffix(); 

甚至像

一样直接
1.DisplayWithSuffix();

【讨论】:

  • 可能是这里最简洁的答案。
  • 我认为这是最干净的方法
  • 最好的答案。这实际上依赖于数字作为文本,而不是试图使用一些复杂的数学公式。这正是人类大脑本身的计算方式,这是理想的。
  • 这是一个很好的答案,但如果该方法称为 DisplayWithSuffix,则返回的答案应包含数字,因此 1 将返回“1st”而不仅仅是“st”。
  • 您可能希望将num.ToString() 放入变量中。不知道有人会如何认为这个答案简单、干净或老实说很快。
【解决方案3】:

不,.NET 基类库中没有内置功能。

【讨论】:

  • 这是一个迟到的评论,但是否有计划将此功能添加到 .NET BCL 以格式化日期?
  • 2019 年现在怎么样?
【解决方案4】:

@nickf:这是 C# 中的 PHP 函数:

public static string Ordinal(int number)
{
    string suffix = String.Empty;

    int ones = number % 10;
    int tens = (int)Math.Floor(number / 10M) % 10;

    if (tens == 1)
    {
        suffix = "th";
    }
    else
    {
        switch (ones)
        {
            case 1:
                suffix = "st";
                break;

            case 2:
                suffix = "nd";
                break;

            case 3:
                suffix = "rd";
                break;

            default:
                suffix = "th";
                break;
        }
    }
    return String.Format("{0}{1}", number, suffix);
}

【讨论】:

  • 谢谢,正要贴出我写的代码。无论如何,我认为你的 String.Format 位比我的要好。
  • 1) 为什么要转换成十进制?一个简单的(number / 10) % 10 就可以了。 2)为什么要把suffix初始化成一个永远不会被使用的值?
  • @CodesInChaos:如果不转换为十进制,则会出现编译器错误:The call is ambiguous between the following methods or properties: 'System.Math.Floor(decimal)' and 'System.Math.Floor(double)'。将suffix 初始化为String.Empty 主要是一种习惯,但也有助于避免意外的Use of unassigned local variable 'suffix' 错误。
  • @ScottDorman 1) 仅当您离开对 Floor 的调用时,这对整数来说是无意义的。整数除法简单地截断为零,无需转换为十进制或使用Floor(number / 10) % 10 更简单且有效。 2) 如果您忽略了代码路径,则会发生这些错误。编译器错误会告诉您修复该错误,而不是默默地返回一个无用的值。
【解决方案5】:

这已经被覆盖了,但我不确定如何链接到它。这是代码片段:

    public static string Ordinal(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 + "st";
            case 2: return number + "nd";
            case 3: return number + "rd";
            default: return number + "th";
        }
    }

仅供参考:这是一种扩展方法。如果您的 .NET 版本低于 3.5,只需删除 this 关键字

[编辑]:感谢您指出它不正确,这就是您复制/粘贴代码得到的结果:)

【讨论】:

  • 不起作用。 1011 % 10 == 1。第 1011 次不正确。
  • 我喜欢你声明变量且从不使用它的方式。
  • @MattMitchell 在您的示例中,它将是第 10110 个而不是第 1011 个
  • @EOLeary 不确定您在说什么,但我认为 Marshall 的编辑适合我的示例。
  • 为什么使用浮点数而不是普通整数?我会使用(number / 10) % 10
【解决方案6】:

这是一个 Microsoft SQL Server 函数版本:

CREATE FUNCTION [Internal].[GetNumberAsOrdinalString]
(
    @num int
)
RETURNS nvarchar(max)
AS
BEGIN

    DECLARE @Suffix nvarchar(2);
    DECLARE @Ones int;  
    DECLARE @Tens int;

    SET @Ones = @num % 10;
    SET @Tens = FLOOR(@num / 10) % 10;

    IF @Tens = 1
    BEGIN
        SET @Suffix = 'th';
    END
    ELSE
    BEGIN

    SET @Suffix = 
        CASE @Ones
            WHEN 1 THEN 'st'
            WHEN 2 THEN 'nd'
            WHEN 3 THEN 'rd'
            ELSE 'th'
        END
    END

    RETURN CONVERT(nvarchar(max), @num) + @Suffix;
END

【讨论】:

  • 我几乎是一字不差地写了这个函数!区别:master db,cast而不是convert,而且我使用的缩进略有不同。伟大的头脑,我猜......
  • +1 - 只是需要一个 SQL 版本 - 帮我写了一个
  • 非常棒,但前提是我们从 SQL 中获取。但在这种情况下,我正在格式化一个 .net DateTime 变量。但这个功能将非常有用。
【解决方案7】:

我知道这不是对 OP 问题的回答,但是因为我发现从这个线程中提升 SQL Server 函数很有用,所以这里有一个 Delphi (Pascal) 等价物:

function OrdinalNumberSuffix(const ANumber: integer): string;
begin
  Result := IntToStr(ANumber);
  if(((Abs(ANumber) div 10) mod 10) = 1) then // Tens = 1
    Result := Result + 'th'
  else
    case(Abs(ANumber) mod 10) of
      1: Result := Result + 'st';
      2: Result := Result + 'nd';
      3: Result := Result + 'rd';
      else
        Result := Result + 'th';
    end;
end;

..., -1st, 0th 有意义吗?

【讨论】:

    【解决方案8】:

    另一种风味:

    /// <summary>
    /// Extension methods for numbers
    /// </summary>
    public static class NumericExtensions
    {
        /// <summary>
        /// Adds the ordinal indicator to an integer
        /// </summary>
        /// <param name="number">The number</param>
        /// <returns>The formatted number</returns>
        public static string ToOrdinalString(this int number)
        {
            // Numbers in the teens always end with "th"
    
            if((number % 100 > 10 && number % 100 < 20))
                return number + "th";
            else
            {
                // Check remainder
    
                switch(number % 10)
                {
                    case 1:
                        return number + "st";
    
                    case 2:
                        return number + "nd";
    
                    case 3:
                        return number + "rd";
    
                    default:
                        return number + "th";
                }
            }
        }
    }
    

    【讨论】:

    • 其实是一个很好的答案。但它是通用的,即不特定于一个月的日期。我的意思是只有日期。所以100以上可能不适用。
    【解决方案9】:
    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";
    }
    

    【讨论】:

      【解决方案10】:
      else if (choice=='q')
      {
          qtr++;
      
          switch (qtr)
          {
              case(2): strcpy(qtrs,"nd");break;
              case(3):
              {
                 strcpy(qtrs,"rd");
                 cout<<"End of First Half!!!";
                 cout<<" hteam "<<"["<<hteam<<"] "<<hs;
                 cout<<" vteam "<<" ["<<vteam;
                 cout<<"] ";
                 cout<<vs;dwn=1;yd=10;
      
                 if (beginp=='H') team='V';
                 else             team='H';
                 break;
             }
             case(4): strcpy(qtrs,"th");break;
      

      【讨论】:

      • 来吧。你在写什么?这与我的问题无关。
      【解决方案11】:

      我认为序数后缀很难获得...您基本上必须编写一个使用开关来测试数字并添加后缀的函数。

      语言没有理由在内部提供此功能,尤其是在特定于语言环境的情况下。

      当涉及到要编写的代码量时,你可以比那个链接做得更好,但你必须为此编写一个函数......

      【讨论】:

      • 鉴于所有货币本地化字符串等。添加序数后缀似乎有点牵强。
      猜你喜欢
      • 1970-01-01
      • 2012-11-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-11
      • 1970-01-01
      • 1970-01-01
      • 2014-02-25
      相关资源
      最近更新 更多