数字、金额转大写,最新的靠谱实现

568 阅读1分钟

数字转大写一般情况下有两种常用的场景:

1、数字转小写文字序号,比如: 16 -> 一十六 ; 123 -> 一百二十三

2、金额转大写,比如 11.11 -> 拾壹元壹角壹分

符合以上两种情况的请随意享用

需要掌握基础的数组处理方法,比如splice跟slice,以及正则表达式的基本操作,参考

Array.prototype.splice() - JavaScript | MDN (mozilla.org)

正则表达式 - JavaScript | MDN (mozilla.org)

场景一:数字转小写文字序号

    /*数字转小写文字序号 eg: 16 -> 一十六 ; 123 -> 一百二十三*/
    function numbertoUpper(numStr) {
      //数值最大不超过1万亿
      if (isNaN(numStr) || numStr >= 1000000000000) return "无效数字!"; 
      // 11个数字单位,1万亿以内的数位按顺序从左到右对应排列
      let sUnit = ["千","百","十","亿","千","百","十","万","千","百","十"]; 
      //10个小写,以数字为索引取对应的大写(eg: sCapital[8] -> ‘八’)
      let sCapital = ["零","一","二","三","四","五","六","七","八","九"]; 
      sUnit.splice(0,sUnit.length - numStr.length + 1); //截取数位
      let sOutput = "";
      for (let i = 0, len = numStr.length; i < len; i++) {
        //拼接数字跟数位
        if (i === len - 1) {
          sOutput += sCapital[Number(numStr.slice(i,i+1))];
        } else {
          sOutput +=sCapital[Number(numStr.slice(i, i + 1))] + sUnit.slice(i, i + 1);
        }
      }
      return sOutput
        .replace(/零[千百十]/g, "零")
        .replace(/零{2,}/g, "零")
        .replace(/零([亿|万])/g, "$1")
        .replace(/亿零{0,3}万/, "亿")
        .replace(/(\S+)零$/g, "$1");
    }

场景二: 小写金额转化大写金额

第一种实现: 将金额数跟数位对应起来,一个for循环搞定,然后通过正则进行过滤,比较推荐这种

    function amountLtoU(amount) {
      //数值最大不超过1万亿
      if (isNaN(amount) || amount >= 1000000000000) return "无效金额!"; 
      //将负号‘-’显示成汉字‘(负)’
      let sPrefix = amount < 0 ? "(负)" : ""; 
      // 当传入的金额没有经过科学计算保留两位小数的话,则用四舍五入进行处理
      amount = Math.round(amount*100)/100; 
      //格式化成两位小数格式(两位小数对应“'角”和“分”)
      let sAmount = Math.abs(amount).toFixed(2); 
      // 14个数字单位,1万亿以内的数位按顺序从左到右对应排列
      let sUnit = ["仟","佰","拾","亿","仟","佰","拾","万","仟","佰","拾","元","角","分"]; 
       // 10个大写数字,以数字为索引取对应的大写(eg: sCapital[8] -> ‘捌’)
      let sCapital = ["零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"];
      //去除小数点(使数字与数位对应)
      sAmount = sAmount.replace(".", ""); 
      //截取当前传入金额对应的数位集合
      sUnit.splice(0,sUnit.length - sAmount.length); 
      let sOutput = "";
      for (let i = 0, len = sAmount.length; i < len; i++) {
        //拼接大写数字与数位
        sOutput +=
          sCapital[Number(sAmount.slice(i, i+1))] + sUnit[i];
      }
      // 返回的时候用正则过滤掉零千、零百、零万等情况
      return (
        sPrefix +
        sOutput
          .replace(/零角零分$/, "整")
          .replace(/零[仟佰拾]/g, "零")
          .replace(/零{2,}/g, "零")
          .replace(/零([亿|万])/g, "$1")
          .replace(/零+元/, "元")
          .replace(/亿零{0,3}万/, "亿")
          .replace(/^元/, "零元")
      );
    }

还有第二种实现:这种方式的,是拆分整数跟小数,分开解析,稍显麻烦

    function digitToUpper(num) {
      let fraction = ["角", "分"];
      let digit = ["零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"];
      let unit = [
        ["元", "万", "亿"],
        ["", "拾", "佰", "仟"],
      ];
      let head = num < 0 ? "欠" : "";
      num = Math.abs(num);
      let out = ""; // 输出
      // 提取小数点后两位 角 分
      for (let i = 0; i < fraction.length; i++) {
        out += (
          digit[Math.floor(num * 10 * Math.pow(10, i)) % 10] + fraction[i]
        ).replace(/零./, "");
      }
      // 小数点后两位是0,标识为“整”
      out = out || "整";
      // 向下取整数
      num = Math.floor(num);
      for (let i = 0; i < unit[0].length && num > 0; i++) {
        let p = "";
        for (let j = 0; j < unit[1].length && num > 0; j++) {
          // 依次取出最低位数进行大写数字转换,并拼接上单位
          p = digit[num % 10] + unit[1][j] + p;
          num = Math.floor(num / 10);
        }
        out = p.replace(/(零.)*零$/, "").replace(/^$/, "零") + unit[0][i] + out;
      }
      return (
        head +
        out
          .replace(/(零.)*零元/, "元")
          .replace(/(零.)+/g, "零")
          .replace(/^整$/, "零元整")
      );
    }

如果以上方案还不满足,可以评论区提出需求,一起讨论交流