處理金額、計量數據時,常需將 12.5000 格式化為 12.5、10.00 為 10。本文提供一個健壯的 trim_trailing_zeros() 函數,支援整數、小數、科學記號、負數,並解析其正則邏輯。
<?php
/**
* 去除數字字串尾部多餘的 0
* @param string|int|float $num 輸入數值或數字字串
* @return string 格式化後的字串(不帶尾部 0,必要時保留小數點)
*/
function trim_trailing_zeros($num): string {
$str = trim((string)$num);
// 1. 純整數或 .000... 形式 → 直接返回整數部分
if (preg_match('/^-?\d+\.0+$/', $str)) {
return preg_replace('/^(-?\d+)\.0+$/', '$1', $str);
}
// 2. 含小數且尾部有 0 → 移除尾部 0
if (preg_match('/^-?\d+\.\d*[1-9]0+$/', $str)) {
return preg_replace('/^(-?\d+\.\d*[1-9])0+$/', '$1', $str);
}
// 3. 科學記號、已無尾部 0、非數字字串 → 原樣返回
return $str;
}
// 測試用例
$tests = [
'12.5000' => '12.5',
'10.00' => '10',
'-3.1400' => '-3.14',
'0.000' => '0',
'100' => '100',
'1.23e-4' => '1.23e-4', // 科學記號不處理
'abc' => 'abc', // 非數字原樣返回
];
foreach ($tests as $input => $expected) {
$out = trim_trailing_zeros($input);
echo "Input: {$input} → Output: {$out} " . ($out === $expected ? '✅' : '❌') . PHP_EOL;
}
?>
| 正則 | 匹配目標 | 替換結果 |
|---|---|---|
| 整數部分 + 小數點 + 全 0 小數 | 保留整數部分(含負號) | |
| 整數部分 + 小數點 + 任意數字 + 非零數字 + 尾部 0 | 保留至最後一個非零數字 |
number_format($num, 2) 先定位數,再去尾零。"12.50 kg"),先提取數字部分處理再拼回。bcmath 或 gmp 避免浮點精度損失,再轉字串處理。<?php
// 方案 1:rtrim 去除字元(簡單但可能誤傷整數部分)
rtrim(rtrim($str, '0'), '.'); // "10.00" → "10" ✅, "100" → "1" ❌
// 方案 2:sprintf 格式化(需知最大小數位)
sprintf('%g', $num); // 自動去尾零,但科學記號閾值不可控
// 方案 3:NumberFormatter (intl 擴展) - 企業級推薦
$fmt = new NumberFormatter('zh_CN', NumberFormatter::DECIMAL);
$fmt->setAttribute(NumberFormatter::MAX_FRACTION_DIGITS, 10);
$fmt->format($num); // 區域化、精確控制
?>