【问题标题】:Format Number like Stack Overflow (rounded to thousands with K suffix)格式数字,如堆栈溢出(以 K 后缀四舍五入到千位)
【发布时间】:2011-01-09 04:50:29
【问题描述】:

如何用 C# 格式化像 SO 这样的数字?

10, 500, 5k, 42k, ...

【问题讨论】:

    标签: c# .net formatting numbers number-formatting


    【解决方案1】:

    像这样:(编辑:已测试)

    static string FormatNumber(int num) {
        if (num >= 100000)
            return FormatNumber(num / 1000) + "K";
    
        if (num >= 10000)
            return (num / 1000D).ToString("0.#") + "K";
    
        return num.ToString("#,0");
    }
    

    例子:

    • 1 => 1
    • 23 => 23
    • 136 => 136
    • 6968 => 6,968
    • 23067 => 23.1K
    • 133031 => 133K

    请注意,这会给 >= 108 的数字提供奇怪的值。
    例如,12345678 变为 12.3KK

    【讨论】:

    • Earwicker 的 12392 会返回什么?
    • @SLaks:太棒了!您可以考虑编辑您的答案以包含此示例。
    • if (num >= 100000000) return FormatNumber(num / 1000000) + "M"; 当然会修复注释。
    • @SLaks - 由于截断而不是四舍五入,此代码会中断 133987 等值。预期:134K。实际:133K。您可以通过在除以 1000 之前将 500 添加到 num 来解决问题,例如FormatNumber((num+500) / 1000) + "K"
    【解决方案2】:

    下面的代码测试到 int.MaxValue 这不是最漂亮的代码,但却是最高效的。 但您可以将其用作:

    123.KiloFormat(); 4332.KiloFormat(); 2332124.KiloFormat(); int.MaxValue.KiloFormat(); (int1 - int2 * int3).KiloFormat();

    等等……

    public static class Extensions
    {
        public static string KiloFormat(this int num)
        {
            if (num >= 100000000)
                return (num / 1000000).ToString("#,0M");
    
            if (num >= 10000000)
                return (num / 1000000).ToString("0.#") + "M";
    
            if (num >= 100000)
                return (num / 1000).ToString("#,0K");
    
            if (num >= 10000)
                return (num / 1000).ToString("0.#") + "K";
    
            return num.ToString("#,0");
        } 
    }
    

    【讨论】:

      【解决方案3】:

      你可以像这样创建一个 CustomFormater:

      public class KiloFormatter: ICustomFormatter, IFormatProvider
      {
          public object GetFormat(Type formatType)
          {
              return (formatType == typeof(ICustomFormatter)) ? this : null;
          }
      
          public string Format(string format, object arg, IFormatProvider formatProvider)
          {
              if (format == null || !format.Trim().StartsWith("K")) {
                  if (arg is IFormattable) {
                      return ((IFormattable)arg).ToString(format, formatProvider);
                  }
                  return arg.ToString();
              }
      
              decimal value = Convert.ToDecimal(arg);
      
              //  Here's is where you format your number
      
              if (value > 1000) {
                  return (value / 1000).ToString() + "k";
              }
      
              return value.ToString();
          }
      }
      

      并像这样使用它:

      String.Format(new KiloFormatter(), "{0:K}", 15600);
      

      编辑:将 CurrencyFormatter 重命名为 KiloFormatter

      【讨论】:

      • @DOK:这是在 .NET Framework 中创建可重用格式化程序的标准方法
      • 嗯,我看不出您的示例中有关如何调用 Format 方法的参数与方法的签名相匹配。 new Kiloformatter() 不是字符串,“{0:K}”可能是对象,15600 不是 IFormatProvider。也许您需要修改答案?
      • @DOK:他的例子是正确的。 msdn.microsoft.com/en-us/library/1ksz8yb7.aspx
      • @SLaks:真的吗? String.Format(new KiloFormatter(), "{0:K}", 15600);匹配方法签名 Format(string, object, IFormatProvider)?
      • 他打电话给String.Format,而不是new KilFormatter().Format
      【解决方案4】:

      SLaks code的略微修改版

      static string FormatNumber(long num)
      {
          if (num >= 100000000) {
              return (num / 1000000D).ToString("0.#M");
          }
          if (num >= 1000000) {
              return (num / 1000000D).ToString("0.##M");
          }
          if (num >= 100000) {
              return (num / 1000D).ToString("0.#k");
          }
          if (num >= 10000) {
              return (num / 1000D).ToString("0.##k");
          }
      
          return num.ToString("#,0");
      }
      

      这将返回以下值:

       123        ->  123
       1234       ->  1,234
       12345      ->  12.35k
       123456     ->  123.4k
       1234567    ->  1.23M
       12345678   ->  12.35M
       123456789  ->  123.5M
      

      【讨论】:

      • 这正是我所需要的。谢谢。
      【解决方案5】:

      我只是写了一些来提供完整的信息

      public static class SIPrefix
      {
          private static List<SIPrefixInfo> _SIPrefixInfoList = new
              List<SIPrefixInfo>();
      
          static SIPrefix()
          {
              _SIPrefixInfoList = new List<SIPrefixInfo>();
              LoadSIPrefix();
          }
      
          public static List<SIPrefixInfo> SIPrefixInfoList
          { 
              get 
              { 
                  SIPrefixInfo[] siPrefixInfoList = new SIPrefixInfo[6];
                  _SIPrefixInfoList.CopyTo(siPrefixInfoList);
                  return siPrefixInfoList.ToList();
              }
          }
      
          private static void LoadSIPrefix()
          {
              _SIPrefixInfoList.AddRange(new SIPrefixInfo[]{
                  new SIPrefixInfo() {Symbol = "Y", Prefix = "yotta", Example = 1000000000000000000000000.00M, ZeroLength = 24, ShortScaleName = "Septillion", LongScaleName = "Quadrillion"},
                  new SIPrefixInfo() {Symbol = "Z", Prefix = "zetta", Example = 1000000000000000000000M, ZeroLength = 21, ShortScaleName = "Sextillion", LongScaleName = "Trilliard"},
                  new SIPrefixInfo() {Symbol = "E", Prefix = "exa", Example = 1000000000000000000M, ZeroLength = 18, ShortScaleName = "Quintillion", LongScaleName = "Trillion"},
                  new SIPrefixInfo() {Symbol = "P", Prefix = "peta", Example = 1000000000000000M, ZeroLength = 15, ShortScaleName = "Quadrillion", LongScaleName = "Billiard"},
                  new SIPrefixInfo() {Symbol = "T", Prefix = "tera", Example = 1000000000000M, ZeroLength = 12, ShortScaleName = "Trillion", LongScaleName = "Billion"},
                  new SIPrefixInfo() {Symbol = "G", Prefix = "giga", Example = 1000000000M, ZeroLength = 9, ShortScaleName = "Billion", LongScaleName = "Milliard"},
                  new SIPrefixInfo() {Symbol = "M", Prefix = "mega", Example = 1000000M, ZeroLength = 6, ShortScaleName = "Million", LongScaleName = "Million"},
                  new SIPrefixInfo() {Symbol = "K", Prefix = "kilo", Example = 1000M, ZeroLength = 3, ShortScaleName = "Thousand", LongScaleName = "Thousand"},
                  new SIPrefixInfo() {Symbol = "h", Prefix = "hecto", Example = 100M, ZeroLength = 2, ShortScaleName = "Hundred", LongScaleName = "Hundred"},
                  new SIPrefixInfo() {Symbol = "da", Prefix = "deca", Example = 10M, ZeroLength = 1, ShortScaleName = "Ten", LongScaleName = "Ten"},
                  new SIPrefixInfo() {Symbol = "", Prefix = "", Example = 1M, ZeroLength = 0, ShortScaleName = "One", LongScaleName = "One"},
              });
          }
      
          public static SIPrefixInfo GetInfo(long amount, int decimals)
          {
              return GetInfo(Convert.ToDecimal(amount), decimals);
          }
      
          public static SIPrefixInfo GetInfo(decimal amount, int decimals)
          {
              SIPrefixInfo siPrefixInfo = null;
              decimal amountToTest = Math.Abs(amount);
      
              var amountLength = amountToTest.ToString("0").Length;
              if(amountLength < 3)
              {
                  siPrefixInfo = _SIPrefixInfoList.Find(i => i.ZeroLength == amountLength).Clone() as SIPrefixInfo;
                  siPrefixInfo.AmountWithPrefix =  Math.Round(amount, decimals).ToString();
      
                  return siPrefixInfo;
              }
      
              siPrefixInfo = _SIPrefixInfoList.Find(i => amountToTest > i.Example).Clone() as SIPrefixInfo;
      
              siPrefixInfo.AmountWithPrefix = Math.Round(
                  amountToTest / Convert.ToDecimal(siPrefixInfo.Example), decimals).ToString()
                                              + siPrefixInfo.Symbol;
      
              return siPrefixInfo;
          }
      }
      
      public class SIPrefixInfo : ICloneable
      {
          public string Symbol { get; set; }
          public decimal Example { get; set; }
          public string Prefix { get; set; }
          public int ZeroLength { get; set; }
          public string ShortScaleName { get; set; }
          public string LongScaleName { get; set; }
          public string AmountWithPrefix { get; set; }
      
          public object Clone()
          {
              return new SIPrefixInfo()
                                  {
                                      Example = this.Example,
                                      LongScaleName = this.LongScaleName,
                                      ShortScaleName = this.ShortScaleName,
                                      Symbol = this.Symbol,
                                      Prefix = this.Prefix,
                                      ZeroLength = this.ZeroLength
                                  };
      
          }
      }
      

      用途:

      var amountInfo = SIPrefix.GetInfo(10250, 2);
      var amountInfo2 = SIPrefix.GetInfo(2500000, 0);
      
      amountInfo.AmountWithPrefix // 10.25K
      amountInfo2.AmountWithPrefix // 2M
      

      【讨论】:

      • 十万户呢?如何获得?
      • 在公斤和兆之间,您可以使用new SIPrefixInfo() {Symbol = "L", Prefix = "Lakh", Example = 100000M, ZeroLength = 5, ShortScaleName = "Lakh", LongScaleName = "Lakh"}, 加十万
      • 非常好.. 我们唯一缺少的是较小的后缀(我猜它应该被称为而不是“pre”,即使你在你以书面形式放在它之后的值之前宣布它,但是我想那是另一个讨论......类似的东西......
      【解决方案6】:

      我知道这是一个非常古老的线程,但我认为更通用的答案可能会很有用:

      ADD:忽略了应该是C#,所以这里翻译一下:

          //--Formats the number after scaling by factors of 1000, and appends a metric unit prefix (e.g. M for *1000000)
          //--Mask, Prov are the standard ToString() parameters (after metric scaling has been performed)
          //--MinPow10 (/Max) should be multipla of 3 and a usually a negative (/Positve) number or zero, if say +9 is used, all is in G or above (/below)
          //--SwitchLimit usualy 1, but could be say 10 or 100 with few/zero decimals, The limit at which to switch prefix, if say 33 then 33000000->33M but 32900000->32900K
          static string FormatMetricPrefix(double Input, String Mask ="F2", IFormatProvider Prov=null, int MinPow10 =-24, int MaxPow10 =24, int SwitchLimit =1) {
              string Prefixes ="yzafpnμm KMGTPEZY";
              int idx=9;
              double tmp=Input;
              if (Input!=0.0) {
                  if (+24<MaxPow10)MaxPow10=+24;
                  if (MinPow10<-24)MaxPow10=-24;
                  idx=(int)Math.Truncate(9.0+Math.Log(Math.Abs(Input/SwitchLimit))/Math.Log(1000.0));
                  if (idx<9+(MinPow10/3)) idx=9+(MinPow10/3); // below lower limit
                  if (9+(MaxPow10/3)<idx) idx=9+(MaxPow10/3); // Above upper limit
                  if (idx<=9)tmp *=Math.Pow(1000.0,9-idx);
                  if (9<idx) tmp /=Math.Pow(1000.0,idx-9);
              }
              if (Prov==null)Prov=CultureInfo.InvariantCulture;
              return tmp.ToString(Mask,Prov)+Prefixes.Substring(idx-1,1).Trim();
          }
      
          static string FormatMetricPrefixF2DK(double Input){return FormatMetricPrefix(Input, Prov:CultureInfo.GetCultureInfo("da-DK"));}
          static string FormatMetricPrefixF2US(double Input){return FormatMetricPrefix(Input, Prov:CultureInfo.GetCultureInfo("en-US"));}
          static string FormatMetricPrefixF0DK(double Input){return FormatMetricPrefix(Input, Mask:"F0", MinPow10:0, Prov:CultureInfo.GetCultureInfo("da-DK"),SwitchLimit:100);}
          static string FormatMetricPrefixF0US(double Input){return FormatMetricPrefix(Input, Mask:"F0", MinPow10:0, Prov:CultureInfo.GetCultureInfo("en-US"),SwitchLimit:100);}
          static void Main(string[] args)
          {
              Console.WriteLine(FormatMetricPrefixF2US(1.234567890E+27));
              Console.WriteLine(FormatMetricPrefixF2US(1234567890));
              Console.WriteLine(FormatMetricPrefixF2US(0.01234567890));
              Console.WriteLine(FormatMetricPrefixF2US(0.00000001234567890));
              Console.WriteLine(FormatMetricPrefixF2US(1.234567890E-26));
              Console.WriteLine(FormatMetricPrefixF0US(0.5));
              Console.WriteLine(FormatMetricPrefixF0US(2));
              Console.WriteLine(FormatMetricPrefixF0US(20000));
              Console.WriteLine(FormatMetricPrefixF0US(87654321));
      
          }
      

      这是针对 SQL 的:

      --Formats the number after scaling by factors of 1000, and appends a metric unit prefix (e.g. M for *1000000)
      --@Mask, @Cult are the standard FORMAT parameters (after metric scaling has been performed)
      --@MinPow10 (/Max) should be multipla of 3 and a usually a negative (/Positve) number or zero, if say +9 is used, all is in G or above (/below)
      --@SwitchLimit usualy 1, but could be say 10 or 100 with few/zero decimals, The limit at which to switch prefix, if say 33 then 33000000->33M but 32900000->32900K
      CREATE function FormatMetricPrefix(@Input float, @Mask Varchar(22)='F2', @Cult Varchar(9)='en-us', @MinPow10 int =-24, @MaxPow10 int =24, @SwitchLimit int=1) returns Varchar(99) as
      Begin
        Declare @Prefixes Varchar(17)='yzafpnμm KMGTPEZY'
        Declare @idx int = 9
        Declare @tmp float=@input
        if @Input<>0.0
        begin
          if +24<@MaxPow10 set @MaxPow10=+24 --highest limit is y 10^24
          if @MinPow10<-24 set @MinPow10=-24 --lowest limit is y 10^-24
          set @idx=9.0+Log(Abs(@input/@SwitchLimit))/Log(1000)
          If @idx<9+(@MinPow10/3) set @idx=9+(@MinPow10/3) -- below lower limit
          If 9+(@MaxPow10/3)<@idx set @idx=9+(@MaxPow10/3) --above upper limit
          if @idx<=9set @tmp=@tmp*POWER(1000.0,9-@idx)
          if 9<@idx set @tmp=@tmp/POWER(1000.0,@idx-9)
        end
        Return FORMAT(@tmp,@mask,@Cult)+LTrim(Substring(@Prefixes,@idx,1))
      end
      GO
      

      然后也许一些相关的包装函数来简化使用,例如

      CREATE function FormatMetricPrefixF2US(@Input float) returns Varchar(99) as
      begin
          return dbo.FormatMetricPrefix(@Input, default,default,default,default,default)
      end
      GO
      CREATE function FormatMetricPrefixF0US(@Input float) returns Varchar(99) as
      begin
          return dbo.FormatMetricPrefix(@Input,  'F0'  ,default,   0   ,default,  100  )
      end
      GO
      

      还有一堆测试/示例:

            Select  0, dbo.FormatMetricPrefixF2US(1.234567890E+27)+'g'
      union Select  1, dbo.FormatMetricPrefixF2US(1234567890)+'g'
      union Select  2, dbo.FormatMetricPrefixF2US(123456789.0)+'g'
      union Select  3, dbo.FormatMetricPrefixF2US(12345678.90)+'g'
      union Select  4, dbo.FormatMetricPrefixF2US(1234567.890)+'g'
      union Select  5, dbo.FormatMetricPrefixF2US(123456.7890)+'g'
      union Select  6, dbo.FormatMetricPrefixF2US(12345.67890)+'g'
      union Select  7, dbo.FormatMetricPrefixF2US(1234.567890)+'g'
      union Select  8, dbo.FormatMetricPrefixF2US(123.4567890)+'g'
      union Select  9, dbo.FormatMetricPrefixF2US(12.34567890)+'g'
      union Select 10, dbo.FormatMetricPrefixF2US(1.234567890)+'g'
      union Select 11, dbo.FormatMetricPrefixF2US(0.1234567890)+'g'
      union Select 12, dbo.FormatMetricPrefixF2US(0.01234567890)+'g'
      union Select 13, dbo.FormatMetricPrefixF2US(0.001234567890)+'g'
      union Select 14, dbo.FormatMetricPrefixF2US(0.0001234567890)+'g'
      union Select 15, dbo.FormatMetricPrefixF2US(0.00001234567890)+'g'
      union Select 16, dbo.FormatMetricPrefixF2US(0.000001234567890)+'g'
      union Select 17, dbo.FormatMetricPrefixF2US(0.0000001234567890)+'g'
      union Select 18, dbo.FormatMetricPrefixF2US(0.00000001234567890)+'g'
      union Select 19, dbo.FormatMetricPrefixF2US(1.234567890E-26)+'g'
      union Select 20, dbo.FormatMetricPrefixF0US(0.5)
      union Select 20, dbo.FormatMetricPrefixF0US(2)
      union Select 21, dbo.FormatMetricPrefixF0US(20000)
      union Select 22, dbo.FormatMetricPrefixF0US(87654321)
      

      【讨论】:

        【解决方案7】:

        我写了这个方法来缩小long的数字:

        public string minifyLong(long value)
            {
                if (value >= 100000000000)
                    return (value / 1000000000).ToString("#,0") + " B";
                if (value >= 10000000000)
                    return (value / 1000000000D).ToString("0.#") + " B";
                if (value >= 100000000)
                    return (value / 1000000).ToString("#,0") + " M";
                if (value >= 10000000)
                    return (value / 1000000D).ToString("0.#") + " M";
                if (value >= 100000)
                    return (value / 1000).ToString("#,0") + " K";
                if (value >= 10000)
                    return (value / 1000D).ToString("0.#") + " K";
                return value.ToString("#,0"); 
            }
        

        【讨论】:

          【解决方案8】:

          我有点晚了,但想出了这个:

          `private static List<Tuple<int, string>> ZeroesAndLetters = new List<Tuple<int, string>>()
          {
              new Tuple<int, string>(15, "Q"),
              new Tuple<int, string>(12, "T"),
              new Tuple<int, string>(9, "B"),
              new Tuple<int, string>(6, "M"),
              new Tuple<int, string>(3, "K"),
          };
          
          public static string GetPointsShortened(ulong num)
          {
              int zeroCount = num.ToString().Length;
              for (int i = 0; i < ZeroesAndLetters.Count; i++)
                  if (zeroCount >= ZeroesAndLetters[i].Item1)
                      return (num / Math.Pow(10, ZeroesAndLetters[i].Item1)).ToString() + ZeroesAndLetters[i].Item2;
              return num.ToString();
          }`
          

          ZeroesAndLetters 列表中添加您需要的数字。

          15、12、9 和 ... 是零的个数,Q、T、B 和 ... 是缩写名称。

          【讨论】:

            【解决方案9】:

            类似这样的:

            string formatted;
            if (num >= 1000) {
                formatted = ((double)num / 1000.0).ToString("N1") + "k";
            } else {
                formatted = num.ToString("N0");
            }
            

            【讨论】:

            • 这将为您的代表打印 36k,而不是 36.8k。 StackOverflow 的版本保留了一些重要的数字。
            【解决方案10】:

            如果数字大于某个阈值,请将其除以 1000,然后将其格式化为所需的小数位数。

            int input = 12392; // for example
            
            if (input >= 10000)
            {
                double thousands = input/1000.0;
                Console.WriteLine(string.Format("{0}K", thousands));
            }
            

            【讨论】:

            • 返回显示的是什么?
            【解决方案11】:
            public static class NumberDisplayHelper
            {
                public static string KiloFormat(this decimal number)
                {
                    return number >= 1000
                        ? $"{(number / 1000):0.##}K"
                        : number.ToString(CultureInfo.CurrentCulture);
                }
            
                public static string KiloFormat(this int number)
                {
                    return number >= 1000
                        ? $"{((decimal)number / 1000):0.##}K"
                        : number.ToString();
                }
            }
            
            [Test()]
            public void KiloFormatter()
            {
                Assert.AreEqual("900", 900m.KiloFormat());
                Assert.AreEqual("1,2K", 1203m.KiloFormat());
                Assert.AreEqual("1,59K", 1588.84m.KiloFormat());
                Assert.AreEqual("1,52K", 1522.84m.KiloFormat());
                Assert.AreEqual("589", 589.KiloFormat());
                Assert.AreEqual("1K", 1001.KiloFormat());
                Assert.AreEqual("1,46K", 1455.KiloFormat());
                Assert.AreEqual("1K", 1000m.KiloFormat());
            }
            

            【讨论】:

              【解决方案12】:

              这是经过适度测试的解决方案四舍五入。它保留meaningfulChars 逗号或点之后的数字,并使用CultureInfo 确定小数分隔符。

              在我写它的时候,我开始明白在大多数情况下不需要四舍五入。因此,如果您不需要四舍五入,则最好使用其他东西或扩展此解决方案。

              我试图确保精度不会被浮点算术吃掉,但我认为它可能会发生在非常大的数字上。

              我也相信这可以通过IFormatProvider 或.NET FW 的类似内在机制来改进。

              public static class ConversionUtilities {
              
                  class ConversionGroup {
                      public ConversionGroup(char symbol, long divider, int power) {
                          Symbol = symbol;
                          Divider = divider;
                          Power = power;
                      }
              
                      public char Symbol;
                      public long Divider;
                      public int Power;
                  }
              
                  private static ConversionGroup[] _conversionGroups = {
                      new ConversionGroup('k', 1000L, 3), 
                      new ConversionGroup('m', 1000000L, 6),
                      new ConversionGroup('b', 1000000000L, 9)
                  };
              
                  /// <summary>
                  /// Converts integer value into string substituting 1 000 -> 1K, 1 000 000 -> 1M, 1 000 000 000 -> 1B
                  /// Rounds to meaingful chars
                  /// </summary>
                  /// <param name="value">value to convert</param>
                  /// <param name="meaninfulChars">round to that many characters after comma</param>
                  /// <param name="uppercase">when set K and M letters will be uppercase</param>
                  /// <returns></returns>
                  public static string ConvertIntToShortStringForm(long value, int meaninfulChars, bool uppercase) {
                      string ret = "";
                      long remainder = 0;
                      long fraction = 0;
                      char symbol = '\0';
                      int maxChars = meaninfulChars;
              
                      for (int i = _conversionGroups.Length - 1; i >= 0; i--) {
                          var group = _conversionGroups[i];
                          if (value >= group.Divider) {
                              if (meaninfulChars < 0) {
                                  maxChars = 0;
                              }
                              else if (meaninfulChars > group.Power) {
                                  maxChars = group.Power;
                              }
              
                              // int maxChars = Math.Clamp(meaninfulChars, 0, group.Power);
                              remainder = value % group.Divider;
                              if (remainder != 0) {
                                  fraction = (long)Math.Round((double)remainder / (Math.Pow(10.0, (double)(group.Power - maxChars))));
                                  if (maxChars == 0) {
                                      if (value / group.Divider + fraction == 1000) {
                                          if (i + 1 == _conversionGroups.Length) {
                                              symbol = group.Symbol;
                                              if (uppercase) {
                                                  symbol = Char.ToUpper(symbol);
                                              }
                                              return string.Format("{0}{1}", value / group.Divider + fraction + group.Symbol);
                                          }
                                          else {
                                              symbol = _conversionGroups[i + 1].Symbol;
                                              if (uppercase) {
                                                  symbol = Char.ToUpper(symbol);
                                              }
                                              return "1" + symbol;
                                          }
                                      } else {
                                          ret += value / group.Divider + fraction;
                                      }
                                  }
                                  else {
                                      ret += value / group.Divider;
                                      ret += CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
                                      ret += fraction;
                                  }
                              }
                              else {
                                  ret += value / group.Divider;
                              }
                              symbol = group.Symbol;
                              if (uppercase) {
                                  symbol = Char.ToUpper(symbol);
                              }
                              ret += symbol;
                              return ret;
                          }
                      }
              
                      return value.ToString();
                  }
              
              }
              

              【讨论】:

                【解决方案13】:

                这是一个截断数字的示例,对于小于 10 亿的数字,最大长度为 6 个字符。

                using System;
                using System.Globalization;
                
                class Program {
                    static void Main(string[] args) 
                    {
                        int num = 0;
                        for(int i = 0; i < 9; i++) 
                        {
                            int factor = i + 1;
                            num += (int)Math.Pow(10, i)*factor;
                            Console.WriteLine($"{num:N0} -> {num.ToStringShort()}");
                        }
                        num += (int)Math.Pow(10, 9);
                        Console.WriteLine($"{num:N0} -> {num.ToStringShort()}");
                    }
                }
                
                public static class NumberExtensions
                {
                    public static string ToStringShort(this int num)
                    {
                        if(num < 1000)
                        {
                            return num.ToString("#0", CultureInfo.CurrentCulture);
                        }
                
                        if(num < 10000)
                        {
                            num /= 10;
                            return (num/100f).ToString("#.00'K'", CultureInfo.CurrentCulture);
                        }
                
                        if(num < 1000000) 
                        {
                            num /= 100;
                            return (num/10f).ToString("#.0'K'", CultureInfo.CurrentCulture);
                        }
                
                        if(num < 10000000)
                        {
                            num /= 10000;
                            return (num/100f).ToString("#.00'M'", CultureInfo.CurrentCulture);
                        }
                
                        num /= 100000;
                        return (num/10f).ToString("#,0.0'M'", CultureInfo.CurrentCulture);
                    }
                }
                

                输出

                1 -> 1
                21 -> 21
                321 -> 321
                4,321 -> 4.32K
                54,321 -> 54.3K
                654,321 -> 654.3K
                7,654,321 -> 7.65M
                87,654,321 -> 87.6M
                987,654,321 -> 987.6M
                1,987,654,321 -> 1,987.6M
                

                【讨论】:

                  【解决方案14】:
                  public static string KFormatter(long num)
                  {
                    if (num >= 1000000000) { return (num / 1000000000D).ToString("0.#", CultureInfo.InvariantCulture).TrimStart(new char[] { '0' }) + "B"; }
                    if (num >= 1000000) { return (num / 1000000D).ToString("0.#", CultureInfo.InvariantCulture).TrimStart(new char[] { '0' }) + "M"; }
                    if (num >= 10000) { return (num / 1000D).ToString("0.#", CultureInfo.InvariantCulture).TrimStart(new char[] { '0' }) + "K"; }
                    return num.ToString("0,#", CultureInfo.InvariantCulture).TrimStart(new char[] { '0' });
                  }
                  

                  【讨论】:

                    【解决方案15】:

                    C#8+ 的解决方案

                     public static string ToKiloFormat(this int num)
                        {
                            return num switch
                            {
                                >= 100000000 => (num / 1000000D).ToString("0.#M"),
                                >= 1000000 => (num / 1000000D).ToString("0.##M"),
                                >= 100000 => (num / 1000D).ToString("0.#k"),
                                >= 10000 => (num / 1000D).ToString("0.##k"),
                                _ => num.ToString("#,0")
                            };
                        }
                    

                    根据之前的回复修改

                    【讨论】:

                      猜你喜欢
                      • 2019-08-31
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2012-09-06
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多