前言
举个例子:10304 -> 一万三百零四;
思路
常量
const numMap = new Array(
"零",
"一",
"二",
"三",
"四",
"五",
"六",
"七",
"八",
"九"
);
const bitMap = new Array("", "十", "百", "千", "万", "", "", "", "亿");
const bitMapLen = bitMap.length;
const numReg = /^(\d+)(\.\d+)?$/;
1、校验数字格式;
typeof num === 'number' && numReg.test(num)
第一个条件是数字类型,第二个排除Infinity、NaN数字
2、拆分整数和小数部分
// 拆分整数 & 小数
function getIntegerAndDecimal(str) {
const group = str.match(numReg);
return [group[1], (group[2] || "").substr(1)];
}
3、整数部分转化为中文
封装一个可以把某一位数转为中文的函数;例如”1000“转成”一千“
思路:如果numStr只有一位从numMap返回映射结果即可;
如果bitMap中有精度映射,拼接后设置len = 1再拼接首位字母即可;(例如10000 -> 一万)
如果bitMap中没有精度映射,两种情况
(1) 十亿亿超出了最大单位;
(2) 一百万没有直接对应的精度单位;
function getNumMaxChinese(numStr) {
let res = "";
let len = numStr.length;
while (len) {
if (len === 1) {
res = numMap[Number(numStr[0])] + res;
return res;
}
// 如果有对应单位
else if (bitMap[len - 1]) {
res = bitMap[len - 1] + res;
len = 1;
} else if (len > bitMapLen) {
res = res + bitMap[bitMapLen - 1];
len = len - (bitMapLen - 1);
} else {
// 魔法数字不好
res = bitMap[4] + res;
len = len - 4;
}
}
}
然后只需要遍历整数部分每一位即可,但是要注意如果最后一位不为0,倒数第二位是0这种情况要在最后一位前加个零;例如1001,为一千零一;
for (let i = 0; i < integer.length; i++) {
if (integer[i] === "0") {
continue;
} else if (i === integer.length - 1 && integer[i - 1] === "0") {
res += "零";
}
res += getNumMaxChinese(
`${integer[i]}${"0".repeat(integer.length - i - 1)}`
);
}
4、小数部分转化为中文
这个只需要在前面加个零,然后遍历从numMap取映射即可
if (decimal) {
res += "点";
for (let i = 0; i < decimal.length; i++) {
res += numMap[decimal[i]];
}
}
测试用例
[0, 1.0343, 10, 1000001, 133, 1030, 10405, 10450, 10400, 1e20] 通过测试;
总结
整体思路还是比较简单常规的,getNumMaxChinese函数处理不够优雅。
欢迎大家指出不符case和讨论更好的方案;
完整代码:
const numMap = new Array(
"零",
"一",
"二",
"三",
"四",
"五",
"六",
"七",
"八",
"九"
);
const bitMap = new Array("", "十", "百", "千", "万", "", "", "", "亿");
const bitMapLen = bitMap.length;
const numReg = /^(\d+)(\.\d+)?$/;
// 通过num位数得到最大的汉字位数,比如120 -> 一百
function getNumMaxChinese(numStr) {
let res = "";
let len = numStr.length;
while (len) {
if (len === 1) {
res = numMap[Number(numStr[0])] + res;
return res;
}
// 如果有对应单位
else if (bitMap[len - 1]) {
res = bitMap[len - 1] + res;
len = 1;
} else if (len > bitMapLen) {
res = res + bitMap[bitMapLen - 1];
len = len - (bitMapLen - 1);
} else {
// 魔法数字不好,取万分位
res = bitMap[4] + res;
len = len - 4;
}
}
}
// 拆分整数 & 小数
function getIntegerAndDecimal(str) {
const group = str.match(numReg);
return [group[1], (group[2] || "").substr(1)];
}
function numToChinese(num) {
if (typeof num !== "number" || !numReg.test(num)) {
return "not number";
}
if (num === 0) return "零";
let res = "";
const numStr = String(num);
const [integer, decimal] = getIntegerAndDecimal(numStr);
for (let i = 0; i < integer.length; i++) {
if (integer[i] === "0") {
continue;
} else if (i === integer.length - 1 && integer[i - 1] === "0") {
res += "零";
}
res += getNumMaxChinese(
`${integer[i]}${"0".repeat(integer.length - i - 1)}`
);
}
if (decimal) {
res += "点";
for (let i = 0; i < decimal.length; i++) {
res += numMap[decimal[i]];
}
}
return res;
}