浏览代码

扩展数字助手类:支持中文大数位单位(万、亿、兆、京、垓)

- 新增中文数位单位配置:万(10^4)、亿(10^8)、兆(10^12)、京(10^16)、垓(10^20)
- 新增 formatToChineseUnits() 方法:支持完整和简化模式的中文数位单位转换
- 新增 formatToSmartChineseUnits() 方法:智能选择合适的中文数位单位
- 新增 parseFromChineseUnits() 方法:中文数位单位反向转换
- 扩展 smartFormatPrecision() 方法:支持中文数位单位选项
- 支持高精度处理,确保40位精度不丢失
- 更新详细的使用说明文档和示例
notfff 7 月之前
父节点
当前提交
5c7faca334
共有 2 个文件被更改,包括 291 次插入4 次删除
  1. 199 4
      UCore/Helper/Number.php
  2. 92 0
      UCore/Helper/README_Number.md

+ 199 - 4
UCore/Helper/Number.php

@@ -13,7 +13,16 @@ class Number
     /** @var int 默认小数精度 */
     const DEFAULT_SCALE = 20;
 
-    /** @var int 万分位转换的基数 */
+    /** @var array 中文数位单位配置 */
+    const CHINESE_UNITS = [
+        'GAI' => ['name' => '垓', 'value' => '100000000000000000000'], // 10^20
+        'JING' => ['name' => '京', 'value' => '10000000000000000'],    // 10^16
+        'ZHAO' => ['name' => '兆', 'value' => '1000000000000'],        // 10^12
+        'YI' => ['name' => '亿', 'value' => '100000000'],              // 10^8
+        'WAN' => ['name' => '万', 'value' => '10000'],                 // 10^4
+    ];
+
+    /** @var int 万分位转换的基数(向后兼容) */
     const WAN_BASE = 10000;
     /**
      * 万分位数据表示转换(高精度版本)
@@ -76,6 +85,109 @@ class Number
         return $result;
     }
 
+    /**
+     * 中文大数位单位转换(高精度版本)
+     *
+     * 支持万、亿、兆、京、垓等中文数位单位
+     * 例如:12345678901234567890 -> "1234垓5678京9012兆3456亿7890万"
+     *
+     * @param int|float|string $number 要转换的数字
+     * @param int $scale 小数精度,默认20位
+     * @param bool $simplify 是否简化显示(只显示最大单位),默认false
+     * @return string 中文数位单位表示的字符串
+     */
+    public static function formatToChineseUnits($number, int $scale = self::DEFAULT_SCALE, bool $simplify = false): string
+    {
+        // 确保输入为字符串格式,保持精度
+        $numStr = (string) $number;
+
+        // 处理负数
+        $isNegative = bccomp($numStr, '0', $scale) < 0;
+        if ($isNegative) {
+            $numStr = bcmul($numStr, '-1', $scale);
+        }
+
+        // 分离整数和小数部分
+        $parts = explode('.', $numStr);
+        $integerPart = $parts[0];
+        $decimalPart = isset($parts[1]) ? $parts[1] : '';
+
+        $result = '';
+        $remainingNumber = $integerPart;
+
+        // 按照从大到小的顺序处理各个单位
+        foreach (self::CHINESE_UNITS as $unitKey => $unitInfo) {
+            $unitValue = $unitInfo['value'];
+            $unitName = $unitInfo['name'];
+
+            if (bccomp($remainingNumber, $unitValue, 0) >= 0) {
+                $unitCount = bcdiv($remainingNumber, $unitValue, 0);
+                $remainingNumber = bcmod($remainingNumber, $unitValue);
+
+                $result .= $unitCount . $unitName;
+
+                // 如果是简化模式,只显示最大单位
+                if ($simplify) {
+                    // 如果还有余数,显示余数
+                    if (bccomp($remainingNumber, '0', 0) > 0) {
+                        $result .= $remainingNumber;
+                    }
+                    break;
+                }
+            }
+        }
+
+        // 如果没有匹配到任何单位,或者还有余数,直接显示数字
+        if (empty($result) || (!$simplify && bccomp($remainingNumber, '0', 0) > 0)) {
+            $result .= $remainingNumber;
+        }
+
+        // 处理小数部分(如果有)
+        if (!empty($decimalPart)) {
+            $decimalPart = rtrim($decimalPart, '0');
+            if (!empty($decimalPart)) {
+                $result .= '.' . $decimalPart;
+            }
+        }
+
+        // 添加负号
+        if ($isNegative) {
+            $result = '-' . $result;
+        }
+
+        return $result;
+    }
+
+    /**
+     * 智能中文数位单位转换
+     *
+     * 根据数字大小自动选择合适的中文单位显示
+     *
+     * @param int|float|string $number 要转换的数字
+     * @param int $scale 小数精度,默认20位
+     * @return string 智能选择的中文数位单位表示
+     */
+    public static function formatToSmartChineseUnits($number, int $scale = self::DEFAULT_SCALE): string
+    {
+        $numStr = (string) $number;
+
+        // 获取绝对值进行判断
+        $absNum = str_replace('-', '', $numStr);
+        $parts = explode('.', $absNum);
+        $integerPart = $parts[0];
+
+        // 根据数字大小选择显示方式
+        foreach (self::CHINESE_UNITS as $unitKey => $unitInfo) {
+            if (bccomp($integerPart, $unitInfo['value'], 0) >= 0) {
+                // 使用简化模式显示最大单位
+                return self::formatToChineseUnits($number, $scale, true);
+            }
+        }
+
+        // 小于万的数字直接显示
+        return $numStr;
+    }
+
     /**
      * 万分位数据表示转换(兼容版本)
      *
@@ -209,6 +321,79 @@ class Number
         return $result;
     }
 
+    /**
+     * 将中文数位单位表示转换回数字(高精度版本)
+     *
+     * 支持万、亿、兆、京、垓等中文数位单位的反向转换
+     * 例如:"1234垓5678京9012兆3456亿7890万" -> "12345678901234567890000000000000"
+     *
+     * @param string $chineseString 中文数位单位表示的字符串
+     * @param int $scale 小数精度,默认20位
+     * @return string 转换后的数字字符串(保持高精度)
+     */
+    public static function parseFromChineseUnits(string $chineseString, int $scale = self::DEFAULT_SCALE): string
+    {
+        // 处理负数
+        $isNegative = str_starts_with($chineseString, '-');
+        if ($isNegative) {
+            $chineseString = substr($chineseString, 1);
+        }
+
+        // 分离整数和小数部分
+        $parts = explode('.', $chineseString);
+        $integerPart = $parts[0];
+        $decimalPart = isset($parts[1]) ? $parts[1] : '';
+
+        $result = '0';
+        $remainingString = $integerPart;
+
+        // 按照从大到小的顺序处理各个单位
+        foreach (self::CHINESE_UNITS as $unitInfo) {
+            $unitValue = $unitInfo['value'];
+            $unitName = $unitInfo['name'];
+
+            $unitPos = mb_strpos($remainingString, $unitName);
+            if ($unitPos !== false) {
+                // 提取单位前的数字
+                $beforeUnit = mb_substr($remainingString, 0, $unitPos);
+                $afterUnit = mb_substr($remainingString, $unitPos + 1);
+
+                if (!empty($beforeUnit)) {
+                    // 计算该单位的值
+                    $unitTotal = bcmul($beforeUnit, $unitValue, $scale);
+                    $result = bcadd($result, $unitTotal, $scale);
+                }
+
+                // 更新剩余字符串
+                $remainingString = $afterUnit;
+            }
+        }
+
+        // 处理剩余的数字(没有单位的部分)
+        if (!empty($remainingString) && is_numeric($remainingString)) {
+            $result = bcadd($result, $remainingString, $scale);
+        }
+
+        // 处理小数部分
+        if (!empty($decimalPart)) {
+            // 去除末尾的0
+            $decimalPart = rtrim($decimalPart, '0');
+            if (!empty($decimalPart)) {
+                // 确保结果是正确的小数格式
+                if (strpos($result, '.') === false) {
+                    $result .= '.' . $decimalPart;
+                }
+            }
+        }
+
+        // 处理负数
+        if ($isNegative) {
+            $result = bcmul($result, '-1', $scale);
+        }
+
+        return $result;
+    }
+
     /**
      * 将万分位表示转换回数字(兼容版本)
      *
@@ -311,17 +496,27 @@ class Number
      * @param int|float|string $number 要格式化的数字
      * @param bool $useWan 是否使用万分位表示,默认true
      * @param int $scale 小数精度,默认20位
+     * @param bool $useChineseUnits 是否使用中文数位单位(万、亿、兆、京、垓),默认false
      * @return string 格式化后的字符串
      */
-    public static function smartFormatPrecision($number, bool $useWan = true, int $scale = self::DEFAULT_SCALE): string
+    public static function smartFormatPrecision($number, bool $useWan = true, int $scale = self::DEFAULT_SCALE, bool $useChineseUnits = false): string
     {
         $numStr = (string) $number;
 
         // 获取整数部分进行比较
         $parts = explode('.', $numStr);
-        $integerPart = $parts[0];
+        $integerPart = str_replace('-', '', $parts[0]);
+
+        // 如果启用中文数位单位,优先使用
+        if ($useChineseUnits) {
+            // 检查是否达到万的级别
+            if (bccomp($integerPart, (string) self::WAN_BASE, 0) >= 0) {
+                return self::formatToSmartChineseUnits($number, $scale);
+            }
+        }
 
-        if ($useWan && bccomp(str_replace('-', '', $integerPart), (string) self::WAN_BASE, 0) >= 0) {
+        // 使用万分位表示
+        if ($useWan && bccomp($integerPart, (string) self::WAN_BASE, 0) >= 0) {
             return self::formatToWanPrecision($number, $scale);
         }
 

+ 92 - 0
UCore/Helper/README_Number.md

@@ -94,6 +94,10 @@ echo Number::smartFormatPrecision('9999.99999999999999999999');
 // 可以禁用万分位表示
 echo Number::smartFormatPrecision('100020.123456789', false);
 // 输出: 100,020.123456789
+
+// 启用中文数位单位
+echo Number::smartFormatPrecision('12345678901234567890', true, 20, true);
+// 输出: 1234京5678901234567890
 ```
 
 ### 6. 高精度千分位格式化 `formatThousandsPrecision()`
@@ -159,6 +163,72 @@ echo Number::truncatePrecision('1234567890.1234567890', 5, 5);
 // 输出: 67890.12345
 ```
 
+### 10. 中文大数位单位转换
+
+#### 中文数位单位转换 `formatToChineseUnits()`
+
+支持万、亿、兆、京、垓等中文数位单位:
+
+```php
+// 完整模式显示所有单位
+echo Number::formatToChineseUnits('12345678901234567890');
+// 输出: 1234京5678兆9012亿3456万7890
+
+echo Number::formatToChineseUnits('123456789012345678901234');
+// 输出: 1234垓5678京9012兆3456亿7890万1234
+
+// 简化模式只显示最大单位
+echo Number::formatToChineseUnits('12345678901234567890', 20, true);
+// 输出: 1234京5678901234567890
+
+// 带小数的转换
+echo Number::formatToChineseUnits('12345678901234567890.123456789');
+// 输出: 1234京5678兆9012亿3456万7890.123456789
+```
+
+#### 智能中文数位单位转换 `formatToSmartChineseUnits()`
+
+自动选择合适的中文单位显示:
+
+```php
+echo Number::formatToSmartChineseUnits('123456789');
+// 输出: 1亿23456789
+
+echo Number::formatToSmartChineseUnits('12345678901234567');
+// 输出: 1京2345678901234567
+
+echo Number::formatToSmartChineseUnits('9999');
+// 输出: 9999 (小于万直接显示)
+```
+
+#### 中文数位单位反向转换 `parseFromChineseUnits()`
+
+将中文数位单位表示转换回数字:
+
+```php
+echo Number::parseFromChineseUnits('1万2345');
+// 输出: 12345
+
+echo Number::parseFromChineseUnits('12亿3456万7890');
+// 输出: 1234567890
+
+echo Number::parseFromChineseUnits('1234京5678兆9012亿3456万7890');
+// 输出: 12345678901234567890
+
+echo Number::parseFromChineseUnits('1万.123456789');
+// 输出: 10000.123456789
+```
+
+#### 支持的中文数位单位
+
+| 单位 | 名称 | 数值 |
+|------|------|------|
+| 万 | 万 | 10^4 |
+| 亿 | 亿 | 10^8 |
+| 兆 | 兆 | 10^12 |
+| 京 | 京 | 10^16 |
+| 垓 | 垓 | 10^20 |
+
 ## 在后台控制器中的使用示例
 
 ### 替换现有的 number_format
@@ -178,17 +248,39 @@ $balance = Number::formatToWan($account->balance);
 ### 在Grid中使用
 
 ```php
+// 使用万分位表示
 $grid->column('balance', '余额')->display(function ($value) {
     return Number::formatToWan($value);
 });
+
+// 使用高精度万分位表示
+$grid->column('balance', '余额')->display(function ($value) {
+    return Number::formatToWanPrecision($value);
+});
+
+// 使用中文数位单位
+$grid->column('amount', '金额')->display(function ($value) {
+    return Number::formatToSmartChineseUnits($value);
+});
+
+// 智能格式化(启用中文数位单位)
+$grid->column('total', '总计')->display(function ($value) {
+    return Number::smartFormatPrecision($value, true, 20, true);
+});
 ```
 
 ### 在Show页面中使用
 
 ```php
+// 使用万分位表示
 $show->field('balance', '余额')->as(function ($value) {
     return Number::formatToWan($value);
 });
+
+// 使用中文数位单位
+$show->field('amount', '金额')->as(function ($value) {
+    return Number::formatToChineseUnits($value, 20, true);
+});
 ```
 
 ## 特性