数字转中文

130 阅读3分钟

前言

  • 闲暇时间抽空整理出来
  • 最近面试被问到
  • js基本功
  • 源码参考

写出一个函数trans,将数字转换成汉语的输出,输入为不超过10000亿的数字

trans(123456) ——> 十二万三千四百五十六

trans(100010001)——> 一亿零一万零一

思考

  1. 首先传入数字,这里面需要注意一个坑,就是js精度问题,当然题目其实已经锁死范围(js最大数保留位数是16位,这中间包括整数部分还有小数部分)
  2. 如果存在小数部分会涉及到四舍五入
  3. 中文单位转换问题,比如小数部分单位['角', '分', '厘', '毫', '微', '纳', '皮']

编写


/**
 * @description:  写出一个函数trans,将数字转换成汉语的输出,输入为不超过10000亿的数字
 *  trans(123456) —— 十二万三千四百五十六元
 *  trans(123456.12) —— 十二万三千四百五十六元一角二分
 *  trans(123456.01) —— 十二万三千四百五十六元一分
    trans(100010001)—— 一亿零一万零一元
 * @param {*} money 是数字 
 * @param {*} isRounding 是否需要四舍五入 默认false 表示截取字符串
 * @return {*}
 */

function trans(money, isRounding = false) {
  //TODO: 这里有个问题是js数字精度问题 js最大保存数字是16位
  let intChineseCurrencyName = '';
  let floatChineseCurrencyName = '';
  if (!money && typeof money !== 'number') {
    throw new Error('不能为空');
  }

  //小数点后面的金额
  const chinesDoteUnit = ['角', '分', '厘', '毫', '微', '纳', '皮'];

  /**
   * @description:
   * @param {*} n 默认字符串
   * @return {*} 返回字符串
   */
  const substrFloatNumber = (n) => {
    let chinesDoteUnitLen = chinesDoteUnit.length;
    if (n.length > chinesDoteUnitLen && isRounding) {
      return (Number('0.' + n).toFixed(chinesDoteUnitLen) + '').split('.')[1];
    }
    return n.substr(0, chinesDoteUnitLen);
  };

  const chineseUpperCurrency = [
    '',
    '十',
    '百',
    '千',
    '万',
    '十万',
    '百万',
    '千万',
    '亿',
    '十亿',
    '百亿',
    '千亿',
    '万亿'
  ];

  const chineseNumberName = [
    '零',
    '一',
    '二',
    '三',
    '四',
    '五',
    '六',
    '七',
    '八',
    '九'
  ];

  const mapNumberToChineseNames = chineseNumberName.reduce(
    (map, nextValue, index) => {
      map.set(index.toString(), nextValue);
      return map;
    },
    new Map()
  );

  const moneyToString = money + '';

  const splitMoneyByDot = moneyToString.split('.');

  // 整数部分
  const integerPartAmount = splitMoneyByDot[0] ? [...splitMoneyByDot[0]] : '';

  //小数部分
  const floatPartAmount = splitMoneyByDot[1]
    ? splitMoneyByDot[1].length > chinesDoteUnit.length
      ? [...substrFloatNumber(splitMoneyByDot[1])]
      : [...splitMoneyByDot[1]]
    : '';

  //整数部分金额单位转换
  const interceptChineseUpperCurrency = chineseUpperCurrency
    .slice(0, integerPartAmount.length)
    .reverse();

  if (integerPartAmount) {
    integerPartAmount.forEach((m, index) => {
      let n = mapNumberToChineseNames.get(m);
      let unit = n === '零' ? '' : interceptChineseUpperCurrency[index];

      if (
        /[十百千万](万|亿)/g.test(intChineseCurrencyName) &&
        /[十百千万]?(万|亿)/.test(unit)
      ) {
        intChineseCurrencyName = intChineseCurrencyName.replace(
          /(?<=[十百千万])(万|亿)/g,
          ''
        );
      }
      intChineseCurrencyName += n + unit;
    });

    intChineseCurrencyName = intChineseCurrencyName
      .replace(/^(一)([十].*?)$/, '$2')
      .replace(/(?<!零)(零)+(?!零)/g, '零')
      .replace(/零$/, '');
  }

  if (floatPartAmount) {
    floatPartAmount.forEach((f, index) => {
      let floatNum = mapNumberToChineseNames.get(f);
      let floatUnit = floatNum === '零' ? '' : chinesDoteUnit[index];
      floatChineseCurrencyName += floatNum + floatUnit;
    });

    floatChineseCurrencyName = floatChineseCurrencyName.replace(/零/g, '');
  }

  return (
    intChineseCurrencyName +
    (intChineseCurrencyName ? '元' : '') +
    floatChineseCurrencyName
  );
}

// const initMoney = 1203111123056;
// const initMoney = 100000000;
// const initMoney = 10000000;
// const initMoney = 1000000;
// const initMoney = 100000;
// const initMoney = 10000;
// const initMoney = 1000;
// const initMoney = 100;
// const initMoney = 10;
// const initMoney = 1;
// const initMoney = 200113;
const initMoney = 12305601001.12345678;
// const initMoney = 1230561.12345678;
// const initMoney = 123456;
// const initMoney = 100010001.123;
// const initMoney = 100010001.010207;
// const initMoney = 100010001.002007;
// const initMoney = 100010001.01020308;
// const initMoney = 1001001.012345891;

console.log('trans(initMoney)', trans(initMoney, true));


分析

  1. 首先将中文需要转换的单位包括数值展示都写全
  2. 传入的数值分为整数部分还有小数部分
  3. 整数部分切割单位转换;小数部分转换切割等
  4. 最后合并

欢迎留言交流更多实现方式