带有千位分隔符的 .NET 通用数字格式

.NET General Number Formatting with Thousands Separator

在 .NET 中是否有可能拥有最紧凑的数字格式,如 "G"eneral Number formatting带有额外的千位分隔符

我无法使用以下内容

String.Format("{0:#,###.###}",32445.324777M)

因为我得到了"32,445.325",而我想要的结果应该是"32.445,325777"。也应该在小数部分使用任意数量的有效数字。

PS:我只需要 decimal 秒。

这就是格式化文化的用武之地。您需要获得符合您要求的格式说明符。您拥有的默认值通常是当前文化、UI 文化或不变文化。您获得的结果表明您使用的是美国文化。

如果您有特定的文化想要输出数字,请使用它。如果没有,您可以创建自己的:

var nfi = 
  new NumberFormatInfo 
  { 
    NumberDecimalSeparator = ",", 
    NumberGroupSeparator = "." 
  };

var ci = 
  new CultureInfo(CultureInfo.InvariantCulture.LCID) { NumberFormat = nfi };

return string.Format(ci, "{0:#,###.########}", 32445.324777M)

如果您还想获得最紧凑的数字,则必须使用自己的代码。最简单的方法是尝试两者,return 较小的结果字符串。

如果您愿意,您仍然可以使用 string.Format 语法 - 您可以编写自己的 ICustomFormatter 来处理:

void Main()
{
    var number = 32445.324777M;

    string.Format(new MyNumberFormatter(),  "{0:MyG}", number).Dump();
}

class MyNumberFormatter : IFormatProvider, ICustomFormatter
{
  public object GetFormat(Type type)
  {
    return this;
  }

  public string Format(string fmt, object arg, IFormatProvider formatProvider)
  {
    if (fmt != "MyG" || !(arg is decimal)) return string.Format(CultureInfo.CurrentCulture, "{0:" + fmt + "}", arg);

    return "Hi";
  }
}

这个实现有点老套,当然,我相信你能找到更好的例子。但它确实有效。在 Format 方法中,您可以选择更适合给定数字的格式,或者甚至只是尝试使用通常的 ToString("G", CultureInfo.InvariantCulture) 并将小数点分隔符添加到该字符串。随心所欲:)

来自.NET documentation

The "#" custom format specifier serves as a digit-placeholder symbol. If the value that is being formatted has a digit in the position where the "#" symbol appears in the format string, that digit is copied to the result string.

Otherwise, nothing is stored in that position in the result string. Note that this specifier never displays a zero that is not a significant digit, even if zero is the only digit in the string. It will display zero only if it is a significant digit in the number that is being displayed.

The "##" format string causes the value to be rounded to the nearest digit preceding the decimal, where rounding away from zero is always used. For example, formatting 34.5 with "##" would result in the value 35.

无法使用默认格式设置格式设置未指定数量的小数位。因此,如果需要,您应该考虑编写自己的实现。

关于小数点和千位分隔符,这取决于您的系统设置,但您可以使用不同的区域性来覆盖它们,正如@Luaan 在他的回答中所描述的那样。

您或许还应该研究一下 this answer

如果您想完全控制,请创建您自己的格式化程序,如下所示。请参阅案例 "U" 了解您的格式。

public class CustomerFormatter : IFormatProvider, ICustomFormatter
{
    public object GetFormat(Type formatType)
    {
        if (formatType == typeof(ICustomFormatter))
            return this;
        else
            return null;
    }

    public string Format(string format,
                          object arg,
                          IFormatProvider formatProvider)
    {
        if (!this.Equals(formatProvider))
        {
            return null;
        }
        else
        {
            // generic formatter if no formater specified
            if (String.IsNullOrEmpty(format))
                format = "G";

            // not a decimal type object
            if (!(arg is decimal))
                return null;

            // get value
            decimal val = (decimal)arg;

            // convert value into generic culture string for control of format
            string valueString = val.ToString();

            // get string in required format type
            format = format.ToUpper();
            switch (format)
            {
                // our user format
                case "U":

                    // get decimals
                    string decimals = val.ToString("G", CultureInfo.InvariantCulture);
                    decimals = decimals.Substring(decimals.IndexOf('.') + 1);

                    // get current culture info
                    NumberFormatInfo nfi = new CultureInfo(CultureInfo.CurrentCulture.Name).NumberFormat;

                    // set our separators
                    nfi.NumberGroupSeparator = ",";
                    nfi.NumberDecimalSeparator = ".";

                    // set numebr of decimals
                    nfi.NumberDecimalDigits = decimals.Length;

                    // convert value to our format
                    valueString = val.ToString("N", nfi);
                    break;
                default:
                    break;
            }

            return valueString;
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        decimal dec = 32445.324777M;
        Console.WriteLine(String.Format(new CustomerFormatter(), "{0}", dec));
        Console.WriteLine(String.Format(new CustomerFormatter(), "{0:G}", dec));
        Console.WriteLine(String.Format(new CustomerFormatter(), "{0:U}", dec));
        Console.WriteLine(String.Format(new CustomerFormatter(), "{0:T}", dec));

        Console.ReadLine();
    }
}