Skip to content

JavaScript 数字转中文

Published:

将万亿以下的正整数数字转中文

前言

在日常开发中,可能会遇到这样的需求:把数字转换成中文表示,例如,将 45674567 变成“四千五百六十七万四千五百六十七”。这个功能在一些需要展示金额或数字的场景下非常实用,比如发票生成、合同金额展示等。

function toChineseNumber(num) {}

假设我们有一个数字 45674567,目标是将其转换为中文表示,例如“四千五百六十七万四千五百六十七”。

1. 分割数字

首先,我们需要把数字按每四位分割开来。可以用正则表达式来实现这一点:

function toChineseNumber(num) {
  const numStr = num.toString().replace(/(?=(\d{4})+$)/g, ",");
}

2. 转换为数组

我们把分割后的字符串转换为数组,并过滤掉任何空字符串:

function toChineseNumber(num) {
  const numStr = num
    .toString()
    .replace(/(?=(\d{4})+$)/g, ",")
    .split(",")
    .filter(Boolean);
  console.log(numStr);
}

console.log(toChineseNumber(45674567));

3. 数字转中文

为了将数字转换为中文,我们先定义一个数组来映射数字到对应的中文字符:然后,我们创建一个函数 _transform 来处理单个四位数字的转换:

const chars = [
  "零",
  "一",
  "二",
  "三",
  "四",
  "五",
  "六",
  "七",
  "八",
  "九",
  "十",
];

// 转中文
function _transform(n) {
  for (let i = 0; i < n.length; i++) {
    const c = chars[+n[i]];
    console.log(c);
  }
}

4. 添加单位

转为中文数字还不能满足需求,在中文中,数字后面通常会跟着单位,如“十”、“百”、“千”。因此,我们需要一个单位数组。需要注意的是,个位在汉字里面不进行任何表示,所以使用空字符串:

const chars = [
  "零",
  "一",
  "二",
  "三",
  "四",
  "五",
  "六",
  "七",
  "八",
  "九",
  "十",
];
const units = ["", "十", "百", "千"];

// 转中文
function _transform(n) {
  for (let i = 0; i < n.length; i++) {
    const c = chars[+n[i]];
    const u = units[n.length - 1 - i];
    console.log(c, u);
  }
}

接下来要把数字和单位拼接起来。

const chars = [
  "零",
  "一",
  "二",
  "三",
  "四",
  "五",
  "六",
  "七",
  "八",
  "九",
  "十",
];
const units = ["", "十", "百", "千"];

// 转中文
function _transform(n) {
  let result = "";
  for (let i = 0; i < n.length; i++) {
    const c = chars[+n[i]];
    const u = units[n.length - 1 - i];
    result += c + u;
  }
  console.log(result);
}

5. 处理零的情况

看上去似乎没有什么问题。但是,如果字符串数字中间有个0,或者多个0,会是什么样子?

可以看到,当字符串存在 0 时,整个中文看上去都不合理。此时我们需要把字符串中的 0 进行判断。

function _transform(n) {
  let result = "";

  function handleZero(str) {
    return str.replace(/零{2,}/g, "零");
  }

  for (let i = 0; i < n.length; i++) {
    const c = chars[+n[i]];
    let u = units[n.length - 1 - i];
    if (c === chars[0]) {
      u = "";
    }
    result += c + u;
  }
  result = handleZero(result);
  console.log(result);
}

这里我们判断以0开头的字符串,并且使用了正则表达式来处理字符串中存在多个0的情况。

接着,还需要处理字符串以0结尾的情况,我们还需要在正则表达式中匹配结尾一个或者多个0的情况,给它替换成空字符串。

function handleZero(str) {
  return str.replace(/零{2,}/g, "零").replace(/零+$/g, "");
}

6. 整体处理

由于这个函数是将处理四位数字字符串的情况,有了这个 _transform 函数之后,我们再把它放到全局环境中去,那么当我们传递大整数时,循环整个数字字符串,分割成每四位一组让辅助函数来处理。

const chars = [
  "零",
  "一",
  "二",
  "三",
  "四",
  "五",
  "六",
  "七",
  "八",
  "九",
  "十",
];
const units = ["", "十", "百", "千"];

function toChineseNumber(num) {
  function _transform(n) {
    let result = "";

    function handleZero(str) {
      return str.replace(/零{2,}/g, "零");
    }

    for (let i = 0; i < n.length; i++) {
      const c = chars[+n[i]];
      let u = units[n.length - 1 - i];
      if (c === chars[0]) {
        u = "";
      }
      result += c + u;
    }
    result = handleZero(result);
    return result;
  }

  const numStr = num
    .toString()
    .replace(/(?=(\d{4})+$)/g, ",")
    .split(",")
    .filter(Boolean);

  for (let i = 0; i < numStr.length; i++) {
    const part = numStr[i];
    const c = _transform(part);
    console.log(c);
  }
}

7. 整体处理大单位

最后,还需要带上大单位。

const chars = [
  "零",
  "一",
  "二",
  "三",
  "四",
  "五",
  "六",
  "七",
  "八",
  "九",
  "十",
];
const units = ["", "十", "百", "千"];
const bigUnits = ["", "万", "亿"];

function handleZero(str) {
  return str.replace(/零{2,}/g, "零");
}

function toChineseNumber(num) {
  function _transform(n) {
    let result = "";

    for (let i = 0; i < n.length; i++) {
      const c = chars[+n[i]];
      let u = units[n.length - 1 - i];
      if (c === chars[0]) {
        u = "";
      }
      result += c + u;
    }
    result = handleZero(result);
    return result;
  }

  const numStr = num
    .toString()
    .replace(/(?=(\d{4})+$)/g, ",")
    .split(",")
    .filter(Boolean);

  let result = "";

  for (let i = 0; i < numStr.length; i++) {
    const part = numStr[i];
    const c = _transform(part);
    const u = bigUnits[numStr.length - 1 - i];
    result += c + u;
  }
  console.log(result);
}

toChineseNumber(123400001234);

可以看到一个小细节,结果多出来一个万。也就是说,当123400001234 数字有连续的4个0或者结尾全部位0时,万字时不出现的。

const chars = [
  "零",
  "一",
  "二",
  "三",
  "四",
  "五",
  "六",
  "七",
  "八",
  "九",
  "十",
];
const units = ["", "十", "百", "千"];
const bigUnits = ["", "万", "亿"];

function handleZero(str) {
  return str.replace(/零{2,}/g, "零");
}

function toChineseNumber(num) {
  function _transform(n) {
    let result = "";

    for (let i = 0; i < n.length; i++) {
      const c = chars[+n[i]];
      let u = units[n.length - 1 - i];
      if (c === chars[0]) {
        u = "";
      }
      result += c + u;
    }
    result = handleZero(result);
    return result;
  }

  const numStr = num
    .toString()
    .replace(/(?=(\d{4})+$)/g, ",")
    .split(",")
    .filter(Boolean);

  let result = "";

  for (let i = 0; i < numStr.length; i++) {
    const part = numStr[i];
    const c = _transform(part);
    let u = bigUnits[numStr.length - 1 - i];

    if (c === chars[0]) {
      u = "";
    }
    result += c + u;
  }
  result = handleZero(result);
  return result;
}

console.log(toChineseNumber(123400001234));
console.log(toChineseNumber(123400000000));

扩展

如果需要将数字转换为大写的中文表示,例如“壹”、“贰”等,我们可以利用映射表:

const map = {
: "零",
: "壹",
: "贰",
: "叁",
: "肆",
: "伍",
: "陆",
: "柒",
: "捌",
: "玖",
: "拾",
: "佰",
: "仟",
: "萬",
  亿: "亿",
};

function toBigChineseNumber(num) {
  const result = toChineseNumber(num);
  return result
    .split("")
    .map(s => map[s])
    .join("");
}

console.log(toBigChineseNumber(123400001234)); // 输出:壹仟贰佰叁拾肆亿零壹仟贰佰叁拾肆