版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_29238009/article/details/79528531
/**
* 金额转换成英文大写
* @param $money 金额
* @param $curr 货币种类,只能输入里面有的5种货币类型,不存在则return
* @return bool|string
*/
function num_to_eng($money,$curr){
$currency_type = [
'502'=>['US DOLLARS' , 'CENTS'],
'142' => ['YUAN','CENTS'],
'110'=>['HONG KONG DOLLARS', 'CENTS'],
'116'=>['JAPANESE YEN','CENTS'],
'303'=>['POUND STERLING','PENCE'],
'300'=>['EURO','CENTS'],
];
if(!in_array(strval($curr),array_keys($currency_type)))
return '';
$enws=array(
0=>"zero",1=>"one",2=>"two",3=>"three",4=>"four",
5=>"five",6=>"six",7=>"seven",8=>"eight",9=>"nine",
10=>"ten",11=>"eleven",12=>"twelve",
13=>"thirteen",14=>"fourteen", 15=>"fifteen",
16=>"sixteen",17=>"seventeen",18=>"eighteen",19=>"nineteen",
20=>"twenty",30=>"thirty",40=>"forty",50=>"fifty",
60=>"sixty",70=>"seventy",80=>"eighty",90=>"ninety");
$unit = [
0 => '',
1 => 'thousand ',
2 => 'million ',
3 => 'billion ',
];
//保留两位小数
$money = round($money,2);
//分割整数位和小数位
$int_deci = explode('.',$money);
//保存整数位
$int = $int_deci[0];
//超过千亿,报错
if(strlen($int) > 12)
return false;
//不存在小数位则填上 ‘00’
if(isset($int_deci[1]))
$deci = substr(floatval($money*100),-2); //这里要用string函数去提取小数位,用intval floatval会有精度问题,如0.80变成0.79
else
$deci = '00';
$int = [
0 => intval($int % 1000), // 个位
1 => intval(intval($int / 1000) % 1000), // 千位
2 => intval(intval($int / (1000 * 1000)) % 1000), //百万位
3 => intval(intval($int / (1000 * 1000 * 1000)) % 1000), //十亿位
];
$str = '';
//处理整数位,下面的字符拼接,都后置位留空,前置位不留空
foreach($int as $k=>$v){
if($v <= 0) continue;
$single = intval($v % 10); //个位
$ten = intval(intval($v / 10) % 10); //十位
$hund = intval(intval($v / 100) % 10); //百位
$sub_str = '';
if($hund > 0)
$sub_str .= $enws[$hund].' hundred ';
if($ten > 0 || $single > 0){
if($ten == 0){
$sub_str .= 'and '.$enws[$single].' ';
}elseif($ten == 1){
$sub_str .= 'and '.$enws[$ten*10+$single].' ';
}else{
$sub_str .= 'and '.$enws[$ten*10].' ';
if($single > 0)
$sub_str .= $enws[$single].' ';
}
}
$sub_str .= $unit[$k];
$str = $sub_str.$str;
}
$str = 'SAY '.$currency_type[$curr][0].' '.$str;
//处理分数
$single = intval($deci % 10); //个位
$ten = intval(intval($deci / 10) % 10); //十位
if($ten > 0 || $single > 0){
if($ten == 0){
$str .= $currency_type[$curr][1].' '.$enws[$single].' ';
}elseif($ten == 1){
$str .= $currency_type[$curr][1].' '.$enws[$ten*10+$single].' ';
}else{
$str .= $currency_type[$curr][1].' '.$enws[$ten*10].' ';
if($single > 0)
$str .= $enws[$single].' ';
}
}
$str .= 'only';
$str = strtoupper($str);
return $str;
}
/**
* 金额转换成中文大写
* @param $money 金额
* @param bool $complex 是否繁体,默认true繁体
* @return bool|mixed|string
*/
function num_to_rmb($money,$complex=true){
if($complex){
$unit1 = ['元','万','亿'];
$unit2 = ['','拾','佰','仟'];
$unit3 = ['零','壹','贰','叁','肆','伍','陆','柒','捌','玖'];
$unit4 = ['角','分'];
$zheng = '整';
}else{
$unit1 = ['元','万','亿'];
$unit2 = ['','十','百','千'];
$unit3 = ['零','一','二','三','四','五','六','七','八','九'];
$unit4 = ['角','分'];
$zheng = '整';
}
//保留两位小数
$money = round($money,2);
//分割整数位和小数位
$int_deci = explode('.',$money);
//保存整数位
$int = $int_deci[0];
//超过千亿,报错
if(strlen($int) > 12)
return false;
//不存在小数位则填上 ‘00’
if(isset($int_deci[1]))
$deci = substr(floatval($money*100),-2); //这里要用string函数去提取小数位,用intval floatval会有精度问题,如0.80变成0.79
else
$deci = '00';
$int = [
0 => intval($int % 10000), // 个位
1 => intval(intval($int / 10000) % 10000), // 万位
2 => intval(intval($int / (10000 * 10000)) % 10000), //亿位
];
$str = '';
//处理整数位
foreach($int as $k=>$v){
if($v <= 0) continue;
$single = intval($v % 10); //个位
$ten = intval(intval($v / 10) % 10); //十位
$hund = intval(intval($v / 100) % 10); //百位
$kilo = intval(intval($v / 1000) % 10); //千位
$sub_str = '';
$sub_str .= $unit3[$kilo].$unit2[3];
$sub_str .= $unit3[$hund].$unit2[2];
$sub_str .= $unit3[$ten].$unit2[1];
$sub_str .= $unit3[$single].$unit2[0];
$sub_str .= $unit1[$k];
$str = $sub_str.$str;
}
//处理分数位
$fen = intval($deci % 10);
$jiao = intval(intval($deci / 10) % 10);
$str .= $unit3[$jiao].$unit4[0]; //角位
$str .= $unit3[$fen].$unit4[1]; //分位
//中文规则变换
for($i=0;$i<3;$i++){
$str = str_replace($unit3[0].$unit1[0],$unit1[0],$str); // 零元 -》 元
$str = str_replace($unit3[0].$unit1[1],$unit1[1],$str); // 零万 -》 万
$str = str_replace($unit3[0].$unit1[2],$unit1[2],$str); // 零亿 -》 亿
$str = str_replace($unit3[0].$unit4[0],$unit3[0],$str); // 零角 -》 零
$str = str_replace($unit3[0].$unit4[1],$unit3[0],$str); // 零分 -》 零
$str = str_replace($unit3[0].$unit2[1],$unit3[0],$str); // 零十 -》 零
$str = str_replace($unit3[0].$unit2[2],$unit3[0],$str); // 零百 -》 零
$str = str_replace($unit3[0].$unit2[3],$unit3[0],$str); // 零千 -》 零
$str = str_replace($unit3[0].$unit3[0],$unit3[0],$str); // 零零 -》 零 ,上面的零十零千可能会变成零零,重复3次差不多能把所有零零归并成一个零字了
//$str = str_replace($unit3[1].$unit2[1],$unit2[1],$str); // 一十 -》 十
$str = mb_trim($str,$unit3[0]); //除去两边的零
}
//不存在分位置,加上 整 字
if(intval($fen)<=0)
$str .= $zheng;
return $str;
}
/**
* trim处理汉字可能会乱码,重写mb_trim解决这个问题
* @param $string 需要处理的字符串
* @param $target 需要trim的字符串
* @return string
*/
function mb_trim($string,$target){
for($i=0;$i<1000;$i++){ //最多处理1000次
$modify = false;
$lchar = mb_substr($string,0,mb_strlen($target));
$rchar = mb_substr($string,-mb_strlen($target),mb_strlen($target));
if($lchar == $target){
$modify = true;
$string = mb_substr($string,mb_strlen($target));
}
if($rchar == $target){
$modify = true;
$string = mb_substr($string,0,mb_strlen($string)-mb_strlen($target));
}
if(!$modify)break;
}
return $string;
}
使用:
$num = '123456789.6';
$eng = num_to_eng($num,142);
$ch = num_to_rmb($num);
var_dump([$num,$ch,$eng]);
上面的方法有些思路有参考其他网上的转换方法,但是基本是我自己设计写出来的,可能会有bug,所以大家用之前请自己测试一下~有bug希望在本文留下言,万分感谢。
原来公司的项目这部分的转换方法是直接从网上找的,本来不是什么复杂的功能,但是在后期应用的时候(很久很久以后)发现金额和大写金额对不上,会有一毛钱或者一分钱的误差,很明显就是原来的方法有循环未完全的问题,或者计算精度有问题了。
后面我自己写一遍,以及同事看原来的方法发现,原来的方法里面,在计算后面两位小数的时候,会采用进位两位,然后再用intval() 或者 (int) 类型强制转换小数,然后导致精度有问题,这是语言自身的问题。当然同时也是大多数语言例如JS会存在的问题,这也是计算机底层的问题。所以各位在需要处理高精度数字(例如计算金额)的时候采用其他方法(百度一下,有人已经解决高精度运算的问题的了,这里我就不多说了),不要简单粗暴地加减乘除。
然后我也发现在使用trim的时候,处理中文会发生乱码的现象,查了下php的trim不完全支持中文。。。所以我自己写了个mb_trim()的方法去适配中文(在这里我用着是没什么问题的,如果你要用在其他地方也是请你先测试一下,然后发现有bug在本文留言给我,3Q~)
最后再补充一下,上面的金额转中英文大写的规则,是按照外贸书写规则的(大概吧。。。其实我也不是很确定,但是大致应该差不多,如果有规则上的问题也请你在留言中提出来~我将会尽快改进)。如果你需要其他格式请自行修改,备注都写好了,解题思路也不难,聪明的你肯定很快就能按需修改了~
That’s all,新年后的第一篇文~( • ̀ω•́ )✧