<?php
$chnNumChar = ["零", "一", "二", "三", "四", "五", "六", "七", "八", "九"];
$chnUnitChar = ["", "十", "百", "千"];
$chnUnitSection = ["", "万", "亿", "万亿"];
$chnValuePair = [
["name" => "十", "value" => 10, "secUnit" => false ],
["name" => "百", "value" => 100, "secUnit" => false ],
["name" => "千", "value" => 1000, "secUnit" => false ],
["name" => "万", "value" => 10000, "secUnit" => true ],
["name" => "亿", "value" => 100000000, "secUnit" => true ]
];
//每节数字转换成中文
function sectionToChinese($section){
global $chnNumChar, $chnUnitChar;
$unitPos = 0;
$zero = true;
$chnStr = '';
while($section > 0){
$v = $section % 10;
if($v == 0){
if(($section == 0) || !$zero){
$zero = true; /*需要补0,zero的作用是确保对连续的多个0,只补一个中文零*/
$chnStr = $chnNumChar[$v].$chnStr;
}
}else{
$zero = false; //至少有一个数字不是0
$strIns = $chnNumChar[$v]; //此位对应的中文数字
$strIns .= $chnUnitChar[$unitPos]; //此位对应的中文权位
$chnStr = $strIns.$chnStr;
}
$unitPos++; //移位
$section = intval($section / 10);
}
return $chnStr;
}
//数字转中文
function numberToChinese($num){
global $chnNumChar, $chnUnitSection;
if($num == 0){
//num == 0需要特殊处理,直接返回"零"
return $chnNumChar[0];
}
$chnStr = '';
$unitPos = 0;
$needZero = false;
while($num > 0){
$section = $num % 10000;
if($needZero){
$chnStr = $chnNumChar[0].$chnStr;
}
$strIns = sectionToChinese($section);
/*是否需要节权位?*/
$strIns .= ($section != 0) ? $chnUnitSection[$unitPos] : $chnUnitSection[0];
$chnStr = $strIns.$chnStr;
/*千位是0?需要在下一个section补零*/
$needZero = ($section < 1000) && ($section > 0);
$num = intval($num / 10000);
$unitPos++;
}
return $chnStr;
}
//单个中文转数字
function chineseToValue($chnStr){
global $chnNumChar;
$chnNumCharLen = count($chnNumChar);
for($i = 0; $i < $chnNumCharLen; $i++){
if($chnStr == $chnNumChar[$i]){
return $i;
}
}
return -1;
}
function chineseToUnit($chnStr, &$secUnit){
global $chnValuePair;
$chnValuePairLen = count($chnValuePair);
for($unit = 0; $unit < $chnValuePairLen; $unit++){
if($chnStr == $chnValuePair[$unit]['name']){
$secUnit = $chnValuePair[$unit]['secUnit'];
return $chnValuePair[$unit]['value'];
}
}
return 1;
}
//中文转数字
function chineseToNumber($chnString){
$rtn = 0;
$section = 0;
$number = 0;
$secUnit = false;
$pos = 0;
$chnCharLen = 1;
$chnStringLen = mb_strlen($chnString);
while($pos < $chnStringLen) {
$curChnChar = mb_substr($chnString, $pos, $chnCharLen);
$num = chineseToValue($curChnChar);
/*数字还是单位?*/
if($num >= 0){
$number = $num;
$pos += $chnCharLen;
//如果是最后一位数字,直接结束
if($pos >= $chnStringLen){
$section += $number;
$rtn += $section;
break;
}
}else{
$curChnChar = mb_substr($chnString, $pos, $chnCharLen);
$unit = chineseToUnit($curChnChar, $secUnit);
//是节权位说明一个节已经结束
if($secUnit){
$section = ($section + $number) * $unit;
$rtn += $section;
$section = 0;
}else{
$section += ($number * $unit);
}
$number = 0;
$pos += $chnCharLen;
if($pos >= $chnStringLen){
$rtn += $section;
break;
}
}
}
return $rtn;
}
$testPair = [
["num" => 0, "chnNumStr" => "零"],
["num" => 1, "chnNumStr" => "一"],
["num" => 2, "chnNumStr" => "二"],
["num" => 3, "chnNumStr" => "三"],
["num" => 4, "chnNumStr" => "四"],
["num" => 5, "chnNumStr" => "五"],
["num" => 6, "chnNumStr" => "六"],
["num" => 7, "chnNumStr" => "七"],
["num" => 8, "chnNumStr" => "八"],
["num" => 9, "chnNumStr" => "九"],
["num" => 10, "chnNumStr" => "一十"],
["num" => 11, "chnNumStr" => "一十一"],
["num" => 110, "chnNumStr" => "一百一十"],
["num" => 111, "chnNumStr" => "一百一十一"],
["num" => 100, "chnNumStr" => "一百"],
["num" => 102, "chnNumStr" => "一百零二"],
["num" => 1020, "chnNumStr" => "一千零二十"],
["num" => 1001, "chnNumStr" => "一千零一"],
["num" => 1015, "chnNumStr" => "一千零一十五"],
["num" => 1000, "chnNumStr" => "一千"],
["num" => 10000, "chnNumStr" => "一万"],
["num" => 20010, "chnNumStr" => "二万零一十"],
["num" => 20001, "chnNumStr" => "二万零一"],
["num" => 100000, "chnNumStr" => "一十万"],
["num" => 1000000, "chnNumStr" => "一百万"],
["num" => 10000000, "chnNumStr" => "一千万"],
["num" => 100000000, "chnNumStr" => "一亿"],
["num" => 1000000000, "chnNumStr" => "一十亿"],
["num" => 1000001000, "chnNumStr" => "一十亿一千"],
["num" => 1000000100, "chnNumStr" => "一十亿零一百"],
["num" => 200010, "chnNumStr" => "二十万零一十"],
["num" => 2000105, "chnNumStr" => "二百万零一百零五"],
["num" => 20001007, "chnNumStr" => "二千万一千零七"],
["num" => 2000100190, "chnNumStr" => "二十亿零一十万零一百九十"],
["num" => 1040010000, "chnNumStr" => "一十亿四千零一万"],
["num" => 200012301, "chnNumStr" => "二亿零一万二千三百零一"],
["num" => 2005010010, "chnNumStr" => "二十亿零五百零一万零一十"],
["num" => 4009060200, "chnNumStr" => "四十亿零九百零六万零二百"],
["num" => 4294967295, "chnNumStr" => "四十二亿九千四百九十六万七千二百九十五"]
];
function testNumberToChinese(){
global $testPair;
$testPairLen = count($testPair);
for($i = 0; $i < $testPairLen; $i++){
$chnNum = numberToChinese($testPair[$i]['num']);
assert($chnNum == $testPair[$i]['chnNumStr'],
'numberToChinese : '.PHP_EOL.
'正确:'.$testPair[$i]['num'].' => '.$testPair[$i]['chnNumStr'].PHP_EOL.
'错误:'.$testPair[$i]['num'].' => '.$chnNum.PHP_EOL);
}
}
function testChineseToNumber(){
global $testPair;
$testPairLen = count($testPair);
for($i = 0; $i < $testPairLen; $i++){
$num = chineseToNumber($testPair[$i]['chnNumStr']);
assert($num == $testPair[$i]['num'],
'chineseToNumber : '.PHP_EOL.
'正确:'.$testPair[$i]['chnNumStr'].' => '.$testPair[$i]['num'].PHP_EOL.
'错误:'.$testPair[$i]['chnNumStr'].' => '.$num.PHP_EOL);
}
}
testNumberToChinese();
testChineseToNumber();