JavaScript阿拉伯数字与中文数字相互转换

有一次在上海前端交换群瞥见有人在群里发了一个乞助信息:

请用JavaScript言语编写一个函数,请求进口参数为数字, 取值局限是一位数整数,返回值是字符串,该函数的功能为:返回该数字对应的汉字,比方:输入数字6,返回汉字“六”;输入数字9,返回汉字“九”。

然后我立马丢了一个之前我写的一个转中文数字的angular过滤器代码

  //- 小写数字转换成大写, 只处置惩罚到[0 ~ 99]
  function numberConvertToUppercase() {
    return function(num) {
      num = Number(num);
      var upperCaseNumber = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '百', '千', '万', '亿'];
      var length = String(num).length;
      if (length == 1) {
        return upperCaseNumber[num];
      } else if (length == 2) {
        if (num == 10) {
          return upperCaseNumber[num];
        } else if (num > 10 && num < 20) {
          return '十' + upperCaseNumber[String(num).charAt(1)];
        } else {
          return upperCaseNumber[String(num).charAt(0)] + '十' + upperCaseNumber[String(num).charAt(1)].replace('零', '');
        }
      }
    }
  }

接下来就有人回应:

  • wolf 你这类写法要命了

  • 才99 就这么长, 假如 99999呢

然后我以项目当时需求就只到2位为由回应。厥后本身去尝试写一个完全的转换要领。尝试了很屡次总是有一些细节没有斟酌全。

经由屡次测试后下面给出一个我终究写出的一个完全版本,供参考:

/**
 * 阿拉伯数字转中文数字,
 * 假如传入数字时则最多处置惩罚到21位,凌驾21位js会自动将数字示意成科学计数法,致使精度丢失和处置惩罚失足
 * 传入数字字符串则没有限定
 * @param {number|string} digit
 */
function toZhDigit(digit) {
  digit = typeof digit === 'number' ? String(digit) : digit;
  const zh = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九'];
  const unit = ['千', '百', '十', ''];
  const quot = ['万', '亿', '兆', '京', '垓', '秭', '穰', '沟', '涧', '正', '载', '极', '恒河沙', '阿僧祗', '那由他', '难以想象', '无量', '大数'];

  let breakLen = Math.ceil(digit.length / 4);
  let notBreakSegment = digit.length % 4 || 4;
  let segment;
  let zeroFlag = [], allZeroFlag = [];
  let result = '';

  while (breakLen > 0) {
    if (!result) { // 第一次实行
      segment = digit.slice(0, notBreakSegment);
      let segmentLen = segment.length;
      for (let i = 0; i < segmentLen; i++) {
        if (segment[i] != 0) {
          if (zeroFlag.length > 0) {
            result += '零' + zh[segment[i]] + unit[4 - segmentLen + i];
            // 推断是不是须要加上 quot 单元
            if (i === segmentLen - 1 && breakLen > 1) {
              result += quot[breakLen - 2];
            }
            zeroFlag.length = 0;
          } else {
            result += zh[segment[i]] + unit[4 - segmentLen + i];
            if (i === segmentLen - 1 && breakLen > 1) {
              result += quot[breakLen - 2];
            }
          }
        } else {
          // 处置惩罚为 0 的情况
          if (segmentLen == 1) {
            result += zh[segment[i]];
            break;
          }
          zeroFlag.push(segment[i]);
          continue;
        }
      }
    } else {
      segment = digit.slice(notBreakSegment, notBreakSegment + 4);
      notBreakSegment += 4;

      for (let j = 0; j < segment.length; j++) {
        if (segment[j] != 0) {
          if (zeroFlag.length > 0) {
            // 第一次实行zeroFlag长度不为0,申明上一个分区末了有0待处置惩罚
            if (j === 0) {
              result += quot[breakLen - 1] + zh[segment[j]] + unit[j];
            } else {
              result += '零' + zh[segment[j]] + unit[j];
            }
            zeroFlag.length = 0;
          } else {
            result += zh[segment[j]] + unit[j];
          }
          // 推断是不是须要加上 quot 单元
          if (j === segment.length - 1 && breakLen > 1) {
            result += quot[breakLen - 2];
          }
        } else {
          // 第一次实行假如zeroFlag长度不为0, 且上一分别不全为0
          if (j === 0 && zeroFlag.length > 0 && allZeroFlag.length === 0) {
            result += quot[breakLen - 1];
            zeroFlag.length = 0;
            zeroFlag.push(segment[j]);
          } else if (allZeroFlag.length > 0) {
            // 实行到末了
            if (breakLen == 1) {
              result += '';
            } else {
              zeroFlag.length = 0;
            }
          } else {
            zeroFlag.push(segment[j]);
          }

          if (j === segment.length - 1 && zeroFlag.length === 4 && breakLen !== 1) {
            // 假如实行到末端
            if (breakLen === 1) {
              allZeroFlag.length = 0;
              zeroFlag.length = 0;
              result += quot[breakLen - 1];
            } else {
              allZeroFlag.push(segment[j]);
            }
          }
          continue;
        }
      }
   

    --breakLen;
  }

  return result;
}

关于中文计数单元可以网上自行搜刮。

上面的代码大致思绪是:

从左至右,先把数字按万分位分组,每组加上对应的单元(万,亿, …), 然后每一个分组举行迭代。breakLen示意可以分红多少个分组,notBreakSegment示意当前已处置惩罚过的分组长度。while轮回中有一个if推断,假如不存在result,则申明是第一次处置惩罚,那末在处置惩罚上是有些差别的。起首,在segment的赋值上,第一次是从0最先,取notBreakSegment的长度,背面每迭代一次notBreakSegment都要在上一个值上加4;其次,第一次处置惩罚不必推断上一个分组是不是全为0的情况,这里zeroFlag示意每一个分组内存在0的个数,allZeroFalg示意当前分组前面涌现的全为0的分组的个数。另外,在第一次实行时,还处置惩罚了只传入为0的情况。

每次处置惩罚segment[i]时,都要先推断当前值是不是为0,为0时则直接记录到zeroFlag,然后进入下一次迭代,假如不为0,起首得推断上一个数字是不是为0, 然后还得依据上一个0是不是位于上一个分组的末位,来增加quot,末了还须要清空标志位。假如当前分组全为0,则标记allZeroFlag,所以在下一个分组处置惩罚时,还须要推断上一个分组是不是全为0

更多细节直接看代码,这里就不多作诠释了。

接下来是中文转阿拉伯数字,这个处置惩罚起来比较简单,这里采纳从右至左的体式格局对每一位举行迭代,直接上代码:

function zhDigitToArabic(digit) {
  const zh = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九'];
  const unit = ['千', '百', '十'];
  const quot = ['万', '亿', '兆', '京', '垓', '秭', '穰', '沟', '涧', '正', '载', '极', '恒河沙', '阿僧祗', '那由他', '难以想象', '无量', '大数'];
  let result = 0, quotFlag;

  for (let i = digit.length - 1; i >= 0; i--) {
    if (zh.indexOf(digit[i]) > -1) { // 数字
      if (quotFlag) {
        result += quotFlag * getNumber(digit[i]);
      } else {
        result += getNumber(digit[i]);
      }
    } else if (unit.indexOf(digit[i]) > -1) { // 非常位
      if (quotFlag) {
        result += quotFlag * getUnit(digit[i]) * getNumber(digit[i - 1]);
      } else {
        result += getUnit(digit[i]) * getNumber(digit[i - 1]);
      }
      --i;
    } else if (quot.indexOf(digit[i]) > -1) { // 万分位
      if (unit.indexOf(digit[i - 1]) > -1) {
        if (getNumber(digit[i - 1])) {
          result += getQuot(digit[i]) * getNumber(digit[i - 1]);
        } else {
          result += getQuot(digit[i]) * getUnit(digit[i - 1]) * getNumber(digit[i - 2]);
          quotFlag = getQuot(digit[i]);
          --i;
        }
      } else {
        result += getQuot(digit[i]) * getNumber(digit[i - 1]);
        quotFlag = getQuot(digit[i]);
      }
      --i;
    }
  }

  return result;

  // 返回中文大写数字对应的阿拉伯数字
  function getNumber(num) {
    for (let i = 0; i < zh.length; i++) {
      if (zh[i] == num) {
        return i;
      }
    }
  }

  // 取单元
  function getUnit(num) {
    for (let i = unit.length; i > 0; i--) {
      if (num == unit[i - 1]) {
        return Math.pow(10, 4 - i);
      }
    }
  }

  // 取分段
  function getQuot(q) {
    for (var i = 0; i < quot.length; i++) {
      if (q == quot[i]) {
        return Math.pow(10, (i + 1) * 4);
      }
    }
  }
}

申明:代码仅供参考,作者只写了一些特别数字和随机数字举行测试,不能保证百分百正确,假如有题目请留言反应。

    原文作者:jenemy
    原文地址: https://segmentfault.com/a/1190000008962568
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞