资讯专栏INFORMATION COLUMN

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

用户84 / 1936人阅读

摘要:然后我立马丢了一个以前我写的一个转中文数字的过滤器代码小写数字转换成大写只处理到零一二三四五六七八九十百千万亿十十零接下来就有人回应你这种写法要命了才就这么长,如果呢然后我以项目当时需求就只到位为由回应。

有一次在上海前端交流群看见有人在群里发了一个求助信息:

请用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);
      }
    }
  }
}

说明:代码仅供参考,作者只写了一些特殊数字和随机数字进行测试,不能保证百分百准确,如果有问题请留言反馈。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/88211.html

相关文章

  • 浅谈javaScript各大运算符

    摘要:除法大前端数字类型与字符串除法运算,同样会先将字符串转为数字类型再做算术运算,同样与布尔类型做算术运算,也是先把布尔类型转换为数字类型再做算术运算,但是遇到字符串里包含有英文或者中文将会得到结果。 算数运算符 包含+、-、*、/、%,下面通过代码示例来给大家进行演示一下;加法: var num=100; var str1=大前端; var str2=300; var boo=true;...

    lykops 评论0 收藏0
  • JavaScript 编程精解 中文第三版 一、值,类型和运算符

    摘要:来源编程精解中文第三版翻译项目原文译者飞龙协议自豪地采用谷歌翻译部分参考了编程精解第版在机器的表面之下,程序在运转。本章将会介绍程序当中的基本元素,包括简单的值类型以及值运算符。示例中的乘法运算符优先级高于加法。 来源:ApacheCN『JavaScript 编程精解 中文第三版』翻译项目原文:Values, Types, and Operators 译者:飞龙 协议:CC BY-NC...

    wh469012917 评论0 收藏0
  • JavaScript-数据类型

    摘要:解释一行,执行一行这也意味着你可以使用同一个变量保存不同类型的数据二数据类型最新的标准定义了种数据类型种原型数据类型布尔值,和一个表明值的特殊关键字。我们称这些类型的值为原始值四布尔值布尔值数据类型只能有两个值,它们是文本和。 一、动态类型 JavaScript 是一种弱类型或者说动态语言。这意味着你不用提前声明变量的类型,在程序运行过程中,类型会被自动确定。(解释一行,执行一行)这也...

    沈俭 评论0 收藏0
  • WebSocket系列之字符串如何二进制数据间进行互相转换

    摘要:总结通过使用和,我们能够在数据和二进制数据中进行互相转换。下一篇系列相关的博客,将会介绍如何通过来向后端传递二进制数据,以及如何处理通过收到的二进制数据。 概述 上一篇博客我们说到了如何进行数字类型(如Short、Int、Long类型)如何在JavaScript中进行二进制转换,如果感兴趣的可以可以阅读本系列第二篇博客——WebSocket系列之JavaScript中数字数据如何转换为...

    stackfing 评论0 收藏0
  • JavaScript学习笔记(一)

    摘要:虽然会输出,但是这只是存在的一个悠久。在的最初版本中使用的是位系统,为了性能考虑使用低位存储变量的类型信息,开头代表是对象,然而表示为全零,所以将它错误的判断为。 参考来源: JavaScript高级程序设计: book.douban.com/subject/105… 千古壹号: github.com/qianguyihao… 小册前端面试之道: juejin.im/book/5bdc71…...

    pingan8787 评论0 收藏0

发表评论

0条评论

用户84

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<