【问题标题】:Shorten long numbers to K/M/B?将长数字缩短为 K/M/B?
【发布时间】:2023-12-30 06:20:01
【问题描述】:

我用谷歌搜索了很多,但根据我的查询,我找不到任何有用的功能。

我想要的是:

100 -> 100
1000 -> 1,000
142840 -> 142,840

但是

2023150 -> 2.023M ( i still want 3 additional numbers for more accuracy )
5430120215 -> 5.430B

如果可能的话,我非常感谢任何自定义函数来动态选择限制。

【问题讨论】:

  • 你不是说Kilo/Mega/Giga 的“K/M/G”,而不是Thousand/Million/Billion

标签: php function helper


【解决方案1】:

使用number_format():

if ($n < 1000000) {
    // Anything less than a million
    $n_format = number_format($n);
} else if ($n < 1000000000) {
    // Anything less than a billion
    $n_format = number_format($n / 1000000, 3) . 'M';
} else {
    // At least a billion
    $n_format = number_format($n / 1000000000, 3) . 'B';
}

如果可能的话,我非常感谢任何自定义函数来动态选择限制。

如果“limit”指的是小数位数(精度),那很简单:

function custom_number_format($n, $precision = 3) {
    if ($n < 1000000) {
        // Anything less than a million
        $n_format = number_format($n);
    } else if ($n < 1000000000) {
        // Anything less than a billion
        $n_format = number_format($n / 1000000, $precision) . 'M';
    } else {
        // At least a billion
        $n_format = number_format($n / 1000000000, $precision) . 'B';
    }

    return $n_format;
}

【讨论】:

  • 有趣!!出于好奇,对 Stack Exchange 如何计算它有任何想法吗?
  • 不是官方的,但这可能是算法*.com/q/3177855/1671639
【解决方案2】:

CakePHP 有一个 Number Helper 和一个方法 toReadableSize。你应该能够理解它并自己想出一些东西。其中$this-&gt;precision基本类似于number_format(),而__n是单复数函数。

【讨论】:

    【解决方案3】:

    我接受了 BoltClock 提供的答案,并在考虑到易于配置的情况下对其进行了一些调整。

    // Shortens a number and attaches K, M, B, etc. accordingly
    function number_shorten($number, $precision = 3, $divisors = null) {
    
        // Setup default $divisors if not provided
        if (!isset($divisors)) {
            $divisors = array(
                pow(1000, 0) => '', // 1000^0 == 1
                pow(1000, 1) => 'K', // Thousand
                pow(1000, 2) => 'M', // Million
                pow(1000, 3) => 'B', // Billion
                pow(1000, 4) => 'T', // Trillion
                pow(1000, 5) => 'Qa', // Quadrillion
                pow(1000, 6) => 'Qi', // Quintillion
            );    
        }
    
        // Loop through each $divisor and find the
        // lowest amount that matches
        foreach ($divisors as $divisor => $shorthand) {
            if (abs($number) < ($divisor * 1000)) {
                // We found a match!
                break;
            }
        }
    
        // We found our match, or there were no matches.
        // Either way, use the last defined value for $divisor.
        return number_format($number / $divisor, $precision) . $shorthand;
    }
    

    【讨论】:

    • 很好的答案凯尔。不过要注意几点:您应该使用if(abs($number) &lt; ($divisor * 1000)) {,否则负数将永远不会缩短。此外,实例化$divisor$shortand 可能是个好主意,只是为了确保当用户可能传递一个空的$divisors 时不会出现异常。谢谢!
    • Lazily return 0 + number_format($number / $divisor, $precision) . $shorthand; 消除尾随无关紧要的零(在我的情况下我不需要)。
    • 我还添加了一个回合,现在这就是我想要的:return 0 + round(number_format($number / $divisor, $precision),1) . $shorthand;
    • 我不知道为什么,但是一旦这个数字越过十亿大关并触及万亿。此方法显示错误“遇到非格式正确的数值”
    【解决方案4】:
    <?php
    // Converts a number into a short version, eg: 1000 -> 1k
    // Based on: http://*.com/a/4371114
    function number_format_short( $n, $precision = 1 ) {
        if ($n < 900) {
            // 0 - 900
            $n_format = number_format($n, $precision);
            $suffix = '';
        } else if ($n < 900000) {
            // 0.9k-850k
            $n_format = number_format($n / 1000, $precision);
            $suffix = 'K';
        } else if ($n < 900000000) {
            // 0.9m-850m
            $n_format = number_format($n / 1000000, $precision);
            $suffix = 'M';
        } else if ($n < 900000000000) {
            // 0.9b-850b
            $n_format = number_format($n / 1000000000, $precision);
            $suffix = 'B';
        } else {
            // 0.9t+
            $n_format = number_format($n / 1000000000000, $precision);
            $suffix = 'T';
        }
      // Remove unecessary zeroes after decimal. "1.0" -> "1"; "1.00" -> "1"
      // Intentionally does not affect partials, eg "1.50" -> "1.50"
        if ( $precision > 0 ) {
            $dotzero = '.' . str_repeat( '0', $precision );
            $n_format = str_replace( $dotzero, '', $n_format );
        }
        return $n_format . $suffix;
    }
    /*
    Example Usage:
    number_format_short(7201); // Output: 7.2k
    Demo:
    echo '<table>';
    for($d = 0; $d < 16; $d++ ) {
        $n = intval("09" . str_repeat( "0", $d ));
        $n = $n / 10;
        echo number_format_short($n) .'<br>'; // 0.9
        $n = intval("1" . str_repeat( "0", $d ));
        echo number_format_short($n) .'<br>'; // 1.0
        $n = intval("11" . str_repeat( "0", $d ));;
        $n = $n / 10;
        echo number_format_short($n) .'<br>'; // 1.1
    }
    echo '</table>';
    Demo Output:
    0.9
    1
    1.1
    
    9
    10
    11
    
    90
    100
    110
    
    0.9K
    1K
    1.1K
    
    9K
    10K
    11K
    
    90K
    100K
    110K
    
    0.9M
    1M
    1.1M
    
    9M
    10M
    11M
    
    90M
    100M
    110M
    
    0.9B
    1B
    1.1B
    
    9B
    10B
    11B
    
    90B
    100B
    110B
    
    0.9T
    1T
    1.1T
    
    9T
    10T
    11T
    
    90T
    100T
    110T
    
    900T
    1,000T
    1,100T
    */
    

    【讨论】:

      【解决方案5】:

      你可以试试这个

       function number_formation($number, $precision = 3) {
              if ($number < 1000000) {
      
                  $formatted_number = number_format($number); /* less than a million */
              } else if ($number < 1000000000) {
      
                  $formatted_number = number_format($number / 1000000, $precision) . 'M'; /* billion */
              } else {
      
                  $formatted_number = number_format($number  / 1000000000, $precision) . 'B'; /* for billion */
              }
      
              return $formatted_number;
          }
      

      【讨论】:

        【解决方案6】:

        试试这个

        function custom_number_format($n, $precision = 1) {
                if ($n < 900) {
                // Default
                 $n_format = number_format($n);
                } else if ($n < 900000) {
                // Thausand
                $n_format = number_format($n / 1000, $precision). 'K';
                } else if ($n < 900000000) {
                // Million
                $n_format = number_format($n / 1000000, $precision). 'M';
                } else if ($n < 900000000000) {
                // Billion
                $n_format = number_format($n / 1000000000, $precision). 'B';
                } else {
                // Trillion
                $n_format = number_format($n / 1000000000000, $precision). 'T';
            }
            return $n_format;
            }
        

        【讨论】:

          【解决方案7】:
          function number_abbr($number)
          {
              $abbrevs = [12 => 'T', 9 => 'B', 6 => 'M', 3 => 'K', 0 => ''];
          
              foreach ($abbrevs as $exponent => $abbrev) {
                  if (abs($number) >= pow(10, $exponent)) {
                      $display = $number / pow(10, $exponent);
                      $decimals = ($exponent >= 3 && round($display) < 100) ? 1 : 0;
                      $number = number_format($display, $decimals).$abbrev;
                      break;
                  }
              }
          
              return $number;
          }
          

          适用于正面和负面。

          【讨论】:

            【解决方案8】:

            尽管很久以前有人问过这个问题,但我有一个不同的解决方案,我认为它更简单:

            function shorten($number){
                $suffix = ["", "K", "M", "B"];
                $precision = 1;
                for($i = 0; $i < count($suffix); $i++){
                    $divide = $number / pow(1000, $i);
                    if($divide < 1000){
                        return round($divide, $precision).$suffix[$i];
                        break;
                    }
                }
            }
            echo shorten(1000);
            

            我希望它仍然对某人有所帮助。

            【讨论】:

              【解决方案9】:

              试试这个。考虑组 k、M、B、T 和 Q(万亿)。任何高于 999Q 的都显示为 999Q+。

              function number(float $num, int $precision = 2): string
              {
                  $absNum = abs($num);
              
                  if ($absNum < 1000)
                  {
                      return (string)round($num, $precision);
                  }
              
                  $groups = ['k','M','B','T','Q'];
              
                  foreach ($groups as $i => $group)
                  {
                      $div = 1000 ** ($i + 1);
              
                      if ($absNum < $div * 1000)
                      {
                          return round($num / $div, $precision) . $group;
                      }
                  }
              
                  return '999Q+';
              }
              

              【讨论】:

                【解决方案10】:

                我在之前的解决方案的基础上采取了不同的方法。基本上它使用log() 函数来摆脱for 语句:

                function number_shorten($number, $precision = 3)
                {
                    $suffixes = ['', 'K', 'M', 'B', 'T', 'Qa', 'Qi'];
                    $index = (int) log(abs($number), 1000);
                    $index = max(0, min(count($suffixes) - 1, $index)); // Clamps to a valid suffixes' index
                    return number_format($number / 1000 ** $index, $precision) . $suffixes[$index];
                }
                

                它适用于正数和负数。

                【讨论】:

                  【解决方案11】:

                  我重构了 OG 最佳答案,让它变得更好和一个功能

                  public function formatNumber($number)
                  {
                      if ($number < 1000000) {
                          // Anything less than a million
                          return number_format($number);
                      } else if ($number < 1000000000) {
                          // Anything less than a billion
                          return number_format($number / 1000000, 0) . 'm';
                      } else {
                          // At least a billion
                          return number_format($number / 1000000000, 0) . 'b';
                      }
                  }
                  

                  【讨论】:

                    【解决方案12】:

                    这是一个非常适合我需要的修改版本。这使我可以指定是否希望 5,500,000 显示为“5.5M”(短样式)或“550 万”(长样式)。

                    function nice_number_format( $n, $style = 'short' ) {
                        if ($n < 1000) {
                            $n_format = number_format($n);
                        } else if ($n < 1000000) {
                            $n_format = floatval(number_format($n / 1000, 2));
                            $suffix = ($style == 'long' ? ' thousand' : 'K');
                        } else if ($n < 1000000000) {
                            $n_format = floatval(number_format($n / 1000000, 2));
                            $suffix = ($style == 'long' ? ' million' : 'M');
                        } else {
                            $n_format = floatval(number_format($n / 1000000000, 2));
                            $suffix = ($style == 'long' ? ' billion' : 'B');
                        } 
                        return $n_format . $suffix;
                    }
                    

                    【讨论】:

                      【解决方案13】:

                      一些修改
                      $precision = 1, 2, 3 or 4 ...

                      function kmb($count, $precision = 2) {
                      if ($count < 1000000) {
                      // Anything less than a million
                      $n_format = number_format($count / 1000) . 'K';
                      } else if ($count < 1000000000) {
                      // Anything less than a billion
                      $n_format = number_format($count / 1000000, $precision) . 'M';
                      } else {
                      // At least a billion
                      $n_format = number_format($count / 1000000000, $precision) . 'B';
                      }
                      return $n_format;
                      }
                      

                      回声 kmb(272937);

                      273K

                      回声 kmb(2729347);

                      273万

                      回声 kmb(2729347874);

                      2.73B

                      【讨论】: