js实现阿拉伯数字转中文,简单易懂

1,449 阅读1分钟

前言

举个例子: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;
}