JS—阿拉伯数字转中文数字

92 阅读4分钟

以下是一个支持正负整数、零、最大到千亿级的数字转中文方法,包含完善的单位处理、零值优化和边界判断,适配日常开发中大部分数字转中文场景(如金额、序号等):

实现思路说明

  1. 范围支持:支持 -999999999999 到 999999999999(千亿级),满足日常场景。
  2. 零值优化:自动处理连续零、段首零、末尾零(如 1001→“一千零一”,而非 “一千零零一”)。
  3. 特殊单位:十位开头自动省略 “一”(如 12→“十二”,而非 “一十二”)。
  4. 输入兼容:支持数字和数字字符串输入,自动处理负号和空格。
  5. 错误处理:对非整数、超出范围的输入抛出明确错误,便于调试。

完整实现代码

/**
 * 数字转中文(支持正负整数、零,最大支持千亿级)
 * @param {number|string} num - 要转换的数字(整数或数字字符串)
 * @returns {string} 中文表示(如 123 → "一百二十三",-456 → "负四百五十六")
 */
function numberToChinese(num) {
  // 1. 基础映射配置
  const digitMap = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九'];
  const unitMap = ['', '十', '百', '千']; // 个级单位(0-3位)
  const sectionUnitMap = ['', '万', '亿', '千亿']; // 段级单位(每4位一段)

  // 2. 预处理输入:转为整数,判断合法性
  let intNum;
  if (typeof num === 'string') {
    // 字符串转整数(去除首尾空格,支持负号)
    intNum = parseInt(num.trim(), 10);
    if (isNaN(intNum)) throw new Error('输入必须是有效整数');
  } else if (typeof num === 'number') {
    if (!Number.isInteger(num)) throw new Error('输入必须是整数');
    intNum = num;
  } else {
    throw new Error('输入必须是数字或数字字符串');
  }

  // 3. 处理边界值:零
  if (intNum === 0) return '零';

  // 4. 处理负数
  const isNegative = intNum < 0;
  intNum = Math.abs(intNum); // 转为正数处理

  // 5. 检查范围(最大支持千亿级:999999999999)
  if (intNum > 999999999999) throw new Error('暂不支持超过千亿的数字');

  // 6. 数字按4位分段(从右往左拆分:个、万、亿、千亿)
  const sections = [];
  let temp = intNum;
  do {
    sections.push(temp % 10000); // 每次取最后4位
    temp = Math.floor(temp / 10000);
  } while (temp > 0);

  // 7. 转换单段数字(4位以内)为中文
  function convertSection(section) {
    let sectionStr = '';
    let hasZero = false; // 标记是否需要加零
    let hasNonZero = false; // 标记段内是否有非零数字

    for (let i = 3; i >= 0; i--) { // 从千位到个位(i=3:千,2:百,1:十,0:个)
      const digit = Math.floor(section / Math.pow(10, i)) % 10;
      if (digit === 0) {
        hasZero = true; // 遇到零,标记需要加零
      } else {
        // 非零数字:如果之前有零,先加“零”
        if (hasZero) sectionStr += digitMap[0];
        sectionStr += digitMap[digit] + unitMap[i]; // 数字+单位(如“三”+“百”=“三百”)
        hasZero = false;
        hasNonZero = true;
      }
    }

    // 特殊处理:十位开头(如 12 → “十二”而非“一十二”)
    if (section >= 10 && section < 100) {
      sectionStr = sectionStr.replace(/^一/, '');
    }

    return hasNonZero ? sectionStr : ''; // 全零段返回空字符串
  }

  // 8. 合并所有段(从高位到低位:千亿→亿→万→个)
  let chineseStr = '';
  for (let i = sections.length - 1; i >= 0; i--) {
    const section = sections[i];
    const sectionChinese = convertSection(section);
    if (sectionChinese) {
      // 处理段间零(如“万”和“个”之间有零,需加“零”)
      if (chineseStr && chineseStr.endsWith(digitMap[0]) === false && section < 1000) {
        chineseStr += digitMap[0];
      }
      chineseStr += sectionChinese + sectionUnitMap[i]; // 段中文+段单位(如“一百”+“万”=“一百万”)
    }
  }

  // 9. 拼接负号(如果是负数)
  return isNegative ? '负' + chineseStr : chineseStr;
}

测试用例(覆盖常见场景)

// 基础测试
console.log(numberToChinese(0)); // 零
console.log(numberToChinese(12)); // 十二(而非“一十二”)
console.log(numberToChinese(105)); // 一百零五
console.log(numberToChinese(1234)); // 一千二百三十四
console.log(numberToChinese(10000)); // 一万
console.log(numberToChinese(10001)); // 一万零一
console.log(numberToChinese(123456)); // 一十二万三千四百五十六
console.log(numberToChinese(100456)); // 一十万零四百五十六
console.log(numberToChinese(99999999)); // 九千九百九十九万九千九百九十九
console.log(numberToChinese(100000000)); // 一亿
console.log(numberToChinese(123456789)); // 一亿二千三百四十五万六千七百八十九
console.log(numberToChinese(999999999999)); // 九千九百九十九亿九千九百九十九万九千九百九十九

// 负数测试
console.log(numberToChinese(-123)); // 负一百二十三
console.log(numberToChinese(-9999)); // 负九千九百九十九

// 字符串输入测试
console.log(numberToChinese('456')); // 四百五十六
console.log(numberToChinese('-789')); // 负七百八十九

// 边界测试(超出范围报错)
try {
  numberToChinese(1000000000000); // 千亿+1,超出范围
} catch (err) {
  console.log(err.message); // 暂不支持超过千亿的数字
}