源码讲解
核心思路主要可以分为以下几个步骤:
- 参数检查与初始化:- 首先,检查传入的 num是否为null。如果是,则直接返回两个空字符串,表示没有数字可转换。
- 初始化一些用于存储结果和处理过程中的变量,如 plainChineseNum(普通中文数字字符串),currencyChineseNum(货币中文数字字符串),zeroCount(用来计数连续零的个数),等等。
 
- 首先,检查传入的 
- 数字转字符串与分割:- 将数字转换为字符串形式,然后根据小数点分割成整数部分和小数部分。
 
- 处理整数部分:- 从最低位(即字符串的最后一位)开始向最高位迭代,这样可以更方便地处理单位(个、十、百、千)。
- 对每个数字:
- 直接转换为对应的中文数字并加到 plainChineseNum的前端。
- 如果数字非零,则添加相应的单位(基础单位加高位单位)到货币表示的字符串中。
- 如果数字是零,特别处理连续零的情况,避免出现多余的“零”。
 
- 直接转换为对应的中文数字并加到 
 
- 处理每个四位小节:- 每当完成一个四位数字的小节,或者到达最左边的数字时,检查并添加高位单位(如万、亿等)。
- 清理并重置用于构建的临时字符串和连续零的计数器。
 
- 处理小数点及小数部分(普通读法):- 如果存在小数部分,添加“点”后,将小数部分的每一位数字转换成中文并追加到 plainChineseNum。
 
- 如果存在小数部分,添加“点”后,将小数部分的每一位数字转换成中文并追加到 
- 处理货币读法的小数部分:- 对货币的小数部分进行特殊处理,第一位表示“角”,第二位表示“分”,注意只有当相应的数字非零时才添加。
 
- 整理和返回结果:- 在最后的货币读法中,清理尾部多余的“零”,并根据是否有小数部分添加“圆整”或“圆”。
- 返回一个对象,包含普通的中文数字读法和货币的中文数字读法。
 
这种方法确保了代码可以有效地转换任意数字到其对应的中文读法,包括较为复杂的货币表示方法。整个过程考虑到了中文数字表达的特点,如单位的正确使用和连续零的合理处理。
定义数字到中文的映射
基本单位(个、十、百、千),以及高位单位(万、亿等)的数组。这些应该在函数外部定义好。
// 数字映射
const numMap = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖']
// 基本单位
const units = ['', '拾', '佰', '仟']
// 高级单位
const highUnits = ['', '万', '亿', '兆']
创建数字转人民币大写的函数。
function convertNumberToChinese(num: number | null): { plainChinese: string, currencyChinese: string } {
  if (num === null) {
    return {
      plainChinese: '',
      currencyChinese: '',
    }
  }
  const numStr = num.toString()
  const [integerPart, decimalPart] = numStr.split('.')
  let plainChineseNum = ''
  let currencyChineseNum = ''
  let zeroCount = 0 // 连续零的计数
  let currencyTemp = '' // 当前处理的小节字符串
  // 处理整数部分
  for (let i = integerPart.length - 1; i >= 0; i--) {
    const digit = Number.parseInt(integerPart[i], 10)
    const position = integerPart.length - 1 - i
    const unit = units[position % 4]
    const highUnit = highUnits[Math.floor(position / 4)]
    // 直接转换为中文数字
    plainChineseNum = numMap[digit] + plainChineseNum
    if (digit !== 0) {
      currencyTemp = numMap[digit] + unit + currencyTemp
      zeroCount = 0 // 重置连续零计数
    }
    else {
      zeroCount++
      if (zeroCount === 1) { // 只在第一次遇到零时添加
        currencyTemp = `零${currencyTemp}`
      }
    }
    // 每完成一个小节或到达最左边一位
    if (position % 4 === 3 || i === 0) {
      if (zeroCount < 4) { // 如果小节中有非零数字
        currencyTemp = currencyTemp + highUnit
      }
      currencyChineseNum = currencyTemp + currencyChineseNum
      currencyTemp = ''
      zeroCount = 0 // 重置连续零计数
    }
  }
  // 添加小数点
  if (decimalPart) {
    plainChineseNum += '点'
    for (let i = 0; i < decimalPart.length; i++) {
      const digit = Number.parseInt(decimalPart[i], 10)
      plainChineseNum += numMap[digit]
    }
  }
  currencyChineseNum = currencyChineseNum.replace(/零+$/, '') // 删除结尾的连续零
  currencyChineseNum += '圆'
  // 处理小数部分
  if (decimalPart) {
    if (decimalPart[0] !== '0')
      currencyChineseNum += `${numMap[Number.parseInt(decimalPart[0])]}角`
    if (decimalPart.length > 1 && decimalPart[1] !== '0')
      currencyChineseNum += `${numMap[Number.parseInt(decimalPart[1])]}分`
  }
  else {
    currencyChineseNum += '整'
  }
  return {
    plainChinese: plainChineseNum,
    currencyChinese: currencyChineseNum,
  }
}
创建人民币大写转数字的函数
interface NumMap {
  [key: string]: number
}
interface UnitMap {
  [key: string]: number
}
const chineseMapping: {
  numbers: NumMap
  basicUnits: UnitMap
  highUnits: UnitMap
} = {
  numbers: { 零: 0, 壹: 1, 贰: 2, 叁: 3, 肆: 4, 伍: 5, 陆: 6, 柒: 7, 捌: 8, 玖: 9 },
  basicUnits: { 拾: 10, 佰: 100, 仟: 1000 },
  highUnits: { 万: 10000, 亿: 100000000, 兆: 1000000000000 },
}
function chineseToArabic(chineseNumber: string): string {
  let total = 0
  let currentTotal = 0 // 用于暂存当前小节的值
  let currentValue = 0 // 当前数字值
  const [integerPart, decimalPart] = chineseNumber.split('圆')
  // 处理整数部分
  for (let i = 0; i < integerPart.length; i++) {
    const char = integerPart[i]
    if (chineseMapping.numbers[char] !== undefined) {
      currentValue = chineseMapping.numbers[char]
    }
    else if (chineseMapping.basicUnits[char] !== undefined) {
      currentTotal += currentValue * chineseMapping.basicUnits[char]
      currentValue = 0
    }
    else if (chineseMapping.highUnits[char] !== undefined) {
      currentTotal += currentValue
      total += currentTotal * chineseMapping.highUnits[char]
      currentTotal = 0 // 重置当前小节总和
      currentValue = 0 // 重置当前数字值
    }
  }
  total += currentTotal + currentValue // 加上最后的小节和剩余的数字
  // 处理小数部分
  let decimalResult = ''
  if (decimalPart) {
    let decimalValue = 0
    let factor = 0.1 // "角" 是十分之一
    for (let i = 0; i < decimalPart.length; i++) {
      const char = decimalPart[i]
      if (chineseMapping.numbers[char] !== undefined) {
        decimalValue += chineseMapping.numbers[char] * factor
        if (factor === 0.1) { // 第一次是"角"
          factor = 0.01 // 下一次是"分"
        }
      }
    }
    decimalResult = decimalValue.toFixed(2).slice(1)
  }
  return total.toString() + decimalResult
}