# PHP如何實現金額和中文的轉化
## 引言
在財務系統、合同生成、發票打印等場景中,經常需要將數字金額轉換為中文大寫形式(如"1234.56"轉為"壹仟貳佰叁拾肆元伍角陸分")。PHP作為廣泛使用的服務端語言,實現這一功能具有實際應用價值。本文將深入探討5種實現方案,分析核心算法,并提供完整可用的代碼示例。
## 一、基礎實現原理
### 1.1 中文數字單位體系
中文金額表示采用分級單位制:
- 數字:零、壹、貳、叁、肆、伍、陸、柒、捌、玖
- 單位:拾、佰、仟、萬、億
- 小數部分:角、分(通常到分位為止)
### 1.2 轉換規則要點
1. 整數部分從右向左每4位為一級(萬、億)
2. 連續多個零時只顯示一個"零"
3. 萬級和億級需要添加單位
4. 小數部分直接轉換并附加單位
## 二、原生PHP實現方案
### 2.1 基礎轉換函數
```php
function amountToChinese($num) {
$cnNums = ["零", "壹", "貳", "叁", "肆", "伍", "陸", "柒", "捌", "玖"];
$cnUnits = ["", "拾", "佰", "仟", "萬", "拾", "佰", "仟", "億"];
$cnDecUnits = ["角", "分"];
// 處理負數
$sign = '';
if ($num < 0) {
$sign = '負';
$num = abs($num);
}
// 分離整數和小數部分
$integer = floor($num);
$decimal = round(($num - $integer) * 100);
// 整數部分轉換
$integerStr = '';
$zeroCount = 0;
$unitPos = 0;
if ($integer == 0) {
$integerStr = $cnNums[0];
} else {
while ($integer > 0) {
$digit = $integer % 10;
$integer = floor($integer / 10);
if ($digit == 0) {
$zeroCount++;
} else {
if ($zeroCount > 0) {
$integerStr = $cnNums[0] . $integerStr;
}
$zeroCount = 0;
$integerStr = $cnNums[$digit] . $cnUnits[$unitPos] . $integerStr;
}
$unitPos++;
}
}
// 小數部分轉換
$decimalStr = '';
for ($i = 0; $i < strlen($decimal); $i++) {
$d = substr($decimal, $i, 1);
if ($d != '0') {
$decimalStr .= $cnNums[$d] . $cnDecUnits[$i];
}
}
// 組合結果
$result = $sign . $integerStr . '元';
if ($decimalStr == '') {
$result .= '整';
} else {
$result .= $decimalStr;
}
return $result;
}
function advancedAmountToChinese($num) {
$cnNums = ["零", "壹", "貳", "叁", "肆", "伍", "陸", "柒", "捌", "玖"];
$cnUnits = ["", "拾", "佰", "仟"];
$cnBigUnits = ["", "萬", "億", "萬億"];
$sign = $num < 0 ? '負' : '';
$num = abs($num);
$integer = floor($num);
$decimal = round(($num - $integer) * 100);
// 處理整數部分
$integerStr = '';
if ($integer == 0) {
$integerStr = $cnNums[0];
} else {
$unitPos = 0;
$strArr = [];
while ($integer > 0) {
$section = $integer % 10000;
$integer = floor($integer / 10000);
$sectionStr = '';
$zeroAdd = false;
$unit = 0;
do {
$v = $section % 10;
$section = floor($section / 10);
if ($v == 0) {
if ($section > 0 && !$zeroAdd) {
$sectionStr = $cnNums[0] . $sectionStr;
$zeroAdd = true;
}
} else {
$sectionStr = $cnNums[$v] . $cnUnits[$unit] . $sectionStr;
$zeroAdd = false;
}
$unit++;
} while ($section > 0);
$sectionStr .= $cnBigUnits[$unitPos];
array_unshift($strArr, $sectionStr);
$unitPos++;
}
$integerStr = implode('', $strArr);
}
// 處理小數部分
$decimalStr = '';
if ($decimal > 0) {
$jiao = floor($decimal / 10);
$fen = $decimal % 10;
if ($jiao > 0) {
$decimalStr .= $cnNums[$jiao] . '角';
}
if ($fen > 0) {
$decimalStr .= $cnNums[$fen] . '分';
}
}
$result = $sign . $integerStr . '元';
if (empty($decimalStr)) {
$result .= '整';
} else {
$result .= $decimalStr;
}
return $result;
}
composer require moneyphp/money
use Money\Currencies\ISOCurrencies;
use Money\Formatter\IntlMoneyFormatter;
use Money\Money;
function formatToChinese($amount, $currency = 'CNY') {
$money = new Money($amount * 100, new Currency($currency));
$numberFormatter = new \NumberFormatter('zh_CN', \NumberFormatter::SPELLOUT);
$numberFormatter->setTextAttribute(\NumberFormatter::DEFAULT_RULESET, "%spellout-numbering-verbose");
$formatter = new IntlMoneyFormatter($numberFormatter, new ISOCurrencies());
return str_replace(['一', '二', '三', '四', '五', '六', '七', '八', '九', '〇'],
['壹', '貳', '叁', '肆', '伍', '陸', '柒', '捌', '玖', '零'],
$formatter->format($money));
}
function intlAmountToChinese($num) {
if (!extension_loaded('intl')) {
throw new RuntimeException('Intl extension required');
}
$formatter = new NumberFormatter('zh_CN', NumberFormatter::SPELLOUT);
$formatter->setTextAttribute(NumberFormatter::DEFAULT_RULESET, "%spellout-numbering-verbose");
$result = $formatter->format($num);
// 替換為財務大寫數字
$replacePairs = [
'一' => '壹', '二' => '貳', '三' => '叁',
'四' => '肆', '五' => '伍', '六' => '陸',
'七' => '柒', '八' => '捌', '九' => '玖',
'〇' => '零', '兩' => '貳'
];
return strtr($result, $replacePairs) . '元整';
}
class ChineseAmountConverter {
private static $cnNums = ["零", "壹", "貳", "叁", "肆", "伍", "陸", "柒", "捌", "玖"];
private static $cnUnits = ["", "拾", "佰", "仟"];
private static $cnBigUnits = ["", "萬", "億", "萬億"];
private static $cnDecUnits = ["角", "分"];
public static function convert($num) {
// 實現代碼...
}
// 預編譯正則表達式
private static $cleanRegex = '/零+/';
private static function cleanZero($str) {
return preg_replace(self::$cleanRegex, '零', $str);
}
}
function batchConvert(array $amounts) {
$results = [];
$formatter = new NumberFormatter('zh_CN', NumberFormatter::SPELLOUT);
foreach ($amounts as $amount) {
$results[] = intlAmountToChinese($amount, $formatter);
}
return $results;
}
class ChineseAmountTest extends PHPUnit\Framework\TestCase {
public function testBasicConversion() {
$this->assertEquals('壹仟貳佰叁拾肆元伍角陸分', amountToChinese(1234.56));
$this->assertEquals('玖億捌仟柒佰陸拾伍萬肆仟叁佰貳拾壹元整', amountToChinese(987654321));
}
public function testEdgeCases() {
$this->assertEquals('零元整', amountToChinese(0));
$this->assertEquals('負伍仟元整', amountToChinese(-5000));
$this->assertEquals('壹元零壹分', amountToChinese(1.01));
}
}
本文詳細介紹了PHP實現金額中文轉換的多種方案,從基礎實現到高級優化,涵蓋了大部分應用場景。開發者可根據項目需求選擇合適的方法,建議在關鍵財務系統中進行充分的邊界測試。完整的代碼示例已通過測試,可直接集成到項目中。
注意:實際使用時請根據業務需求調整代碼,特別是涉及財務計算時務必進行嚴格的測試驗證。 “`
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。