问答题1013/1588写出一个函数trans,将数字转换成汉语的输出,输入为不超过10000亿的数字。

1trans(123456) —— 十二万三千四百五十六 2trans(100010001)—— 一亿零一万零一
难度:
2023-05-15 创建

参考答案:

23.12.18 更新,有同学投稿提供了自己的答案,更加简洁

1function NumToChina(n) { 2 n = n.toString(); 3 let numbers = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九']; 4 if (n === '0') return numbers[0]; 5 let units = ['', '十', '百', '千']; 6 let len = n.length; 7 let res = ''; 8 for (let i = 0; i < len; i++) { 9 let num = Number(n[i]); 10 if (num != 0) { 11 if (n[i - 1] === '0') res = res + numbers[0]; 12 res = res + numbers[num] + units[len - i - 1]; 13 } 14 } 15 if (len == 2 && n[0] == '1') res = res.slice(1); 16 return res; 17} 18 19function numTo(n) { 20 const isLose = n < 0; 21 n = Math.abs(n).toString(); 22 let res = []; 23 let len = n.length; 24 for (let i = len; i > 0; i -= 4) { 25 res.push(NumToChina(n.slice(Math.max(0, i - 4), i))); 26 } 27 const units = ['', '万', '亿']; 28 for (let i = 0; i < res.length; i++) { 29 if (res[i] == '') continue; 30 res[i] = res[i] + units[i]; 31 } 32 isLose && res.push('负'); 33 return res.reverse().join(''); 34} 35numTo(12345);

以下是原答案:

1/** 2 * 阿拉伯数字转中文数字, 3 * 如果传入数字时则最多处理到21位,超过21位js会自动将数字表示成科学计数法,导致精度丢失和处理出错 4 * 传入数字字符串则没有限制 5 * @param {number|string} digit 6 */ 7function toZhDigit(digit) { 8 digit = typeof digit === 'number' ? String(digit) : digit; 9 const zh = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九']; 10 const unit = ['千', '百', '十', '']; 11 const quot = ['万', '亿', '兆', '京', '垓', '秭', '穰', '沟', '涧', '正', '载', '极', '恒河沙', '阿僧祗', '那由他', '不可思议', '无量', '大数']; 12 13 let breakLen = Math.ceil(digit.length / 4); 14 let notBreakSegment = digit.length % 4 || 4; 15 let segment; 16 let zeroFlag = [], allZeroFlag = []; 17 let result = ''; 18 19 while (breakLen > 0) { 20 if (!result) { // 第一次执行 21 segment = digit.slice(0, notBreakSegment); 22 let segmentLen = segment.length; 23 for (let i = 0; i < segmentLen; i++) { 24 if (segment[i] != 0) { 25 if (zeroFlag.length > 0) { 26 result += '零' + zh[segment[i]] + unit[4 - segmentLen + i]; 27 // 判断是否需要加上 quot 单位 28 if (i === segmentLen - 1 && breakLen > 1) { 29 result += quot[breakLen - 2]; 30 } 31 zeroFlag.length = 0; 32 } else { 33 result += zh[segment[i]] + unit[4 - segmentLen + i]; 34 if (i === segmentLen - 1 && breakLen > 1) { 35 result += quot[breakLen - 2]; 36 } 37 } 38 } else { 39 // 处理为 0 的情形 40 if (segmentLen == 1) { 41 result += zh[segment[i]]; 42 break; 43 } 44 zeroFlag.push(segment[i]); 45 continue; 46 } 47 } 48 } else { 49 segment = digit.slice(notBreakSegment, notBreakSegment + 4); 50 notBreakSegment += 4; 51 52 for (let j = 0; j < segment.length; j++) { 53 if (segment[j] != 0) { 54 if (zeroFlag.length > 0) { 55 // 第一次执行zeroFlag长度不为0,说明上一个分区最后有0待处理 56 if (j === 0) { 57 result += quot[breakLen - 1] + zh[segment[j]] + unit[j]; 58 } else { 59 result += '零' + zh[segment[j]] + unit[j]; 60 } 61 zeroFlag.length = 0; 62 } else { 63 result += zh[segment[j]] + unit[j]; 64 } 65 // 判断是否需要加上 quot 单位 66 if (j === segment.length - 1 && breakLen > 1) { 67 result += quot[breakLen - 2]; 68 } 69 } else { 70 // 第一次执行如果zeroFlag长度不为0, 且上一划分不全为0 71 if (j === 0 && zeroFlag.length > 0 && allZeroFlag.length === 0) { 72 result += quot[breakLen - 1]; 73 zeroFlag.length = 0; 74 zeroFlag.push(segment[j]); 75 } else if (allZeroFlag.length > 0) { 76 // 执行到最后 77 if (breakLen == 1) { 78 result += ''; 79 } else { 80 zeroFlag.length = 0; 81 } 82 } else { 83 zeroFlag.push(segment[j]); 84 } 85 86 if (j === segment.length - 1 && zeroFlag.length === 4 && breakLen !== 1) { 87 // 如果执行到末尾 88 if (breakLen === 1) { 89 allZeroFlag.length = 0; 90 zeroFlag.length = 0; 91 result += quot[breakLen - 1]; 92 } else { 93 allZeroFlag.push(segment[j]); 94 } 95 } 96 continue; 97 } 98 } 99 100 --breakLen; 101 } 102 103 return result; 104} 105

从左至右,先把数字按万分位分组,每组加上对应的单位(万,亿, ...),然后每个分组进行迭代。

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。

最近更新时间:2024-07-20

赞赏支持

预览

题库维护不易,您的支持就是我们最大的动力!