1.思路:
按照亿、万、佰、元、角、分,进行分割处理。在亿、万、佰、元之前数额在进一步分割处理。如:‘叁仟肆佰伍拾亿零壹佰陆拾柒万叁仟肆佰伍拾壹元捌角肆分’ 。
第一步是:去掉‘零’和‘整’这样的汉字。
第二步是:拆分为:‘叁仟肆佰伍拾亿,壹佰陆拾柒万,叁仟肆佰伍拾壹元,捌角,肆分’。
第三步是:将‘叁仟肆佰伍拾亿’的‘叁仟肆佰伍拾’处理为数字:‘3450’;同样‘壹佰陆拾柒万’:‘167’;
‘叁仟肆佰伍拾壹’:‘3451’。
第四步:将亿前面处理好的‘3450’ * 100000000;同样‘167’10000、‘3451’1、80.1、40.01。
最后就是相加了:345001673451.84
2.js实现(输入值是stirng类型)
这里使用正则表达式进行单位金额的分割。getInfo()是第三步的处理函数,获取亿、万、佰之前的金额数值。(看到这里已经够了,对金额精度没有要求的够用)
// '叁仟肆佰伍拾亿零壹佰陆拾柒万叁仟肆佰伍拾壹元捌角伍分' => '345001673451.85'
const getMoneyNum = (money) => {
const dic= {
零: 0,
壹: 1,
贰: 2,
叁: 3,
肆: 4,
伍: 5,
陆: 6,
柒: 7,
捌: 8,
玖: 9,
};
// 处理仟,佰,拾;'叁仟肆佰伍拾壹' => '3451'
const getInfo = (item) => {
let itemCount = 0;
// 将仟,佰,拾 拆分数组 '叁仟肆佰伍拾壹' => ['叁仟', '肆佰', '伍拾', '壹']
let arr = item
.replace(/(\w*仟)(\w*)/, "$1,$2")
.replace(/(\w*佰)(\w*)/, "$1,$2")
.replace(/(\w*拾)(\w*)/, "$1,$2")
.split(',')
.filter(_item => {
return _item && _item.trim();
});
// 处理每个单位对应的值
for (let subItem of arr) {
let currValue = 0;
let subArr = subItem.split('');
if (subArr[1] === '拾') {
// 处理拾位
currValue = dic[subArr[0]] * 10;
} else if (subArr[1] === '佰') {
//处理佰位
currValue = dic[subArr[0]] * 100;
} else if (subArr[1] === '仟') {
// 处理仟位
currValue = dic[subArr[0]] * 1000;
} else {
// 处理个位
currValue = dic[subArr[0]];
}
itemCount += currValue;
}
return itemCount;
};
let totalMoney = 0;
// 按照亿,万,拆分成数组;'叁仟肆佰伍拾亿零壹佰陆拾柒万叁仟肆佰伍拾壹元捌角伍分' => ['叁仟肆佰伍拾亿', '壹佰陆拾柒万', '叁仟肆佰伍拾壹元', '捌角', '伍分']
let newMoney = money
.replace(/零/g, '').replace(/整/g, '') // 去掉 '零','整'
.replace(/(\w*亿)(\w*)/, "$1,$2")
.replace(/(\w*万)(\w*)/, "$1,$2")
.replace(/(\w*元)(\w*)/, "$1,$2")
.replace(/(\w*角)(\w*)/, "$1,$2")
.split(',')
.filter(_item => {
return _item && _item.trim();
});
// 按照亿,万及以下单位为组, 循环求解求解数值;
for (let mainItem of newMoney) {
let currMoney = 0;
let mainArr = mainItem.split('');
if (mainArr[mainArr.length - 1] === '亿') {
mainArr.pop(); // 去掉亿单位
currMoney = getInfo(mainArr.join('')) * 100000000; // 求仟,佰,拾
} else if (mainArr[mainArr.length - 1] === '万') {
mainArr.pop(); // 去掉万单位
currMoney = getInfo(mainArr.join('')) * 10000; // 求仟,佰,拾
} else if (mainArr[mainArr.length - 1] === '元') {
mainArr.pop(); // 去掉元
currMoney = getInfo(mainArr.join('')); // 求仟,佰,拾
} else if (mainArr[mainArr.length - 1] === '角') {
mainArr.pop(); // 去掉角
currMoney = dic[mainArr[0]] * 0.1;
} else if (mainArr[mainArr.length - 1] === '分') {
mainArr.pop(); // 去掉分
currMoney = dic[mainArr[0]] * 0.01;
}
totalMoney += currMoney;
}
return totalMoney.toString();
};
3.金额计算使用Decimal进行处理
你会发现在代码中用的是伍分,思路里是肆分。这就是因为js数值计算的误差,经典的题目:0.1+0.2 === 0.3 是true吗?答案是否。所以这里使用Decimal进行金额数值计算。下面给出的ts版本,其实和js一样,哈哈哈哈。
// 引入Decimal yarn add decimal.js 或者 npm install decimal.js --save
import { Decimal } from 'decimal.js';
// 大写汉字转数字;'叁仟肆佰伍拾亿零壹佰陆拾柒万叁仟肆佰伍拾壹' => '345001673451'
export const getMoneyNum = (money: string) => {
// 大写汉字对应的数字
const dic: any = {
零: 0,
壹: 1,
贰: 2,
叁: 3,
肆: 4,
伍: 5,
陆: 6,
柒: 7,
捌: 8,
玖: 9,
};
// 处理仟,佰,拾;'叁仟肆佰伍拾壹' => '3451'
const getInfo = (item: string) => {
let itemCount = new Decimal(0);
// 将仟,佰,拾 拆分数组 '叁仟肆佰伍拾壹' => ['叁仟', '肆佰', '伍拾', '壹']
let arr = item
.replace(/(\w*仟)(\w*)/, "$1,$2")
.replace(/(\w*佰)(\w*)/, "$1,$2")
.replace(/(\w*拾)(\w*)/, "$1,$2")
.split(',')
.filter(_item => {
return _item && _item.trim();
});
// 处理每个单位对应的值
for (let subItem of arr) {
let currValue = new Decimal(0);
let subArr = subItem.split('');
if (subArr[1] === '拾') {
// 处理拾位
currValue = new Decimal(dic[subArr[0]]).mul(new Decimal(10));
} else if (subArr[1] === '佰') {
//处理佰位
currValue = new Decimal(dic[subArr[0]]).mul(new Decimal(100));
} else if (subArr[1] === '仟') {
// 处理仟位
currValue = new Decimal(dic[subArr[0]]).mul(new Decimal(1000));
} else {
// 处理个位
currValue = new Decimal(dic[subArr[0]]);
}
itemCount = new Decimal(itemCount).add(new Decimal(currValue));
}
return itemCount;
};
let totalMoney = new Decimal(0);
/**
* 按照亿,万,元,角,分拆分成数组;
* '叁仟肆佰伍拾亿零壹佰陆拾柒万叁仟肆佰伍拾壹元捌角肆分' => ['叁仟肆佰伍拾亿', '壹佰陆拾柒万', '叁仟肆佰伍拾壹元', '捌角', '肆分']
*/
let newMoney = money
.replace(/零/g, '')
.replace(/整/g, '') // 去掉 '零','整'
.replace(/(\w*亿)(\w*)/, "$1,$2")
.replace(/(\w*万)(\w*)/, "$1,$2")
.replace(/(\w*元)(\w*)/, "$1,$2")
.replace(/(\w*角)(\w*)/, "$1,$2")
.split(',')
.filter(_item => {
return _item && _item.trim();
});
// 按照亿,万及以下单位为组, 循环求解求解数值;
for (let mainItem of newMoney) {
let currMoney = new Decimal(0);
let mainArr = mainItem.split('');
if (mainArr[mainArr.length - 1] === '亿') {
mainArr.pop(); // 去掉亿单位
currMoney = new Decimal(getInfo(mainArr.join(''))).mul(new Decimal(100000000)); // 求仟,佰,拾
} else if (mainArr[mainArr.length - 1] === '万') {
mainArr.pop(); // 去掉万单位
currMoney = new Decimal(getInfo(mainArr.join(''))).mul(new Decimal(10000)); // 求仟,佰,拾
} else if (mainArr[mainArr.length - 1] === '元') {
mainArr.pop(); // 去掉元
currMoney = new Decimal(getInfo(mainArr.join(''))); // 求仟,佰,拾
} else if (mainArr[mainArr.length - 1] === '角') {
mainArr.pop(); // 去掉角
currMoney = new Decimal(dic[mainArr[0]]).mul(new Decimal(0.1));
} else if (mainArr[mainArr.length - 1] === '分') {
mainArr.pop(); // 去掉分
currMoney = new Decimal(dic[mainArr[0]]).mul(new Decimal(0.01));
}
totalMoney = new Decimal(totalMoney).add(new Decimal(currMoney));
}
return totalMoney.toString();
};
4.去除包含其他汉字的大写金额字符串(如“人民币贰佰万元整”得到“贰佰万元”)
这里用的正则表达式进行处理的。我的业务场景是OCR识别营业执照返回的金额有“人民币”啥的字段信息。直接上代码。
// 去除字符串中其他文字,获取大写数字金额。如“人民币贰佰万元整”得到“贰佰万元”
const getRealMoney= (value) => {
const regExp = /[零壹贰叁肆伍陆柒捌玖拾佰仟万亿元角分]/g;
return value.match(regExp)?.join('');
};
5.保留金额到万位(输入值是stirng类型;231023310元 => 23102.331万元)
这里要考虑有角分的情况,和最后几位为零的情况。这里也主要是使用正则表达式。看代码。
// 保留金额到万
const getThousand = (money) => {
let resReslut;
const regExp = /\./g;
// 有小数点 102321.10
if (regExp.test('money')) {
resReslut = money
.replace(/(\d*)(\d{4}(?=\.))(\d*)/g, '$1.$2$3') // 102321.10 => 10.2321.10
.replace(/(\d*)(\.)(\d*)(\.)(\d*)/, '$1$2$3$5') // 10.2321.10 => 10.232110
.replace(/0*$/, '') // 去掉最后的'0' 10.232110 => 10.23211
.replace(/\.$/, ''); // 去掉最后的'.'
} else {
// 231023310 => 23102.3310 => 23102.331
resReslut = money
.replace(/(\d)(\d{4}$)/, '$1.$2')
.replace(/0*$/, '') // 去掉最后的'0'
.replace(/\.$/, ''); // 去点最后的'.'
}
return resReslut;
};