博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JavaScript阿拉伯数字与中文数字互相转换
阅读量:5962 次
发布时间:2019-06-19

本文共 6446 字,大约阅读时间需要 21 分钟。

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

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

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

转载地址:http://mrjax.baihongyu.com/

你可能感兴趣的文章
3D地图的定时高亮和点击事件(基于echarts)
查看>>
mysql开启binlog
查看>>
设置Eclipse编码方式
查看>>
分布式系统唯一ID生成方案汇总【转】
查看>>
并查集hdu1232
查看>>
Mysql 监视工具
查看>>
从前后端分离到GraphQL,携程如何用Node实现?\n
查看>>
Linux Namespace系列(09):利用Namespace创建一个简单可用的容器
查看>>
博客搬家了
查看>>
Python中使用ElementTree解析xml
查看>>
jquery 操作iframe、frameset
查看>>
解决vim中不能使用小键盘
查看>>
jenkins权限管理,实现不同用户组显示对应视图views中不同的jobs
查看>>
我的友情链接
查看>>
批量删除用户--Shell脚本
查看>>
Eclipse Java @Override 报错
查看>>
知道双字节码, 如何获取汉字 - 回复 "pinezhou" 的问题
查看>>
linux中cacti和nagios整合
查看>>
Python高效编程技巧
查看>>
js中var self=this的解释
查看>>