【Java】阿拉伯数字转汉字(完全符合中文阅读习惯)(支持所有整数类型)

本文主要是介绍【Java】阿拉伯数字转汉字(完全符合中文阅读习惯)(支持所有整数类型),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Java 阿拉伯数字转汉字

网上看过很多实现,但都有 BUG,不是多余0没有处理,就是很多生成的汉字字符串根本不符合中文阅读习惯(各位代码写完测试的时候用例多搞一点啊)

刚好公司有个项目就要实现这个小功能,顾把自己的实现分享出来


1、结果示例

看代码前,先观察一下结果是否满足各位的预期

用例输入:

int[] nums = {1000, 1024, 10, 100024, 92030003, 90000003, 1, 2, 3, 11};

用例输出:

一千
一千零二十四
十
十万零二十四
九千二百零三万零三
九千万零三
一
二
三
十一

用例基本能覆盖所有特殊场景,支持 Integer.MIN_VALUE - Integer.MAX_VALUE 范围内的所有输入

小数场景没做,因为暂时没这个需要,不过小数场景要更好做一些,毕竟按照中文阅读习惯,小数只要把小数点后的数字一一列出来转换为中文字符就行,没有位数转换的需求

3.14159 -> 三点一四一五九

有小数转换需求的同学,只要把整数部分取出来,用我的代码转换,小数部分再写个简单的函数实现即可

可能有人习惯把"二"读成"两"的,到时候在代码里替换字符就行


2、完整代码

急着用的同学,写个工具类,直接拷贝过去就能用了

/*** @ClassName NumStrConvertor* @Description 阿拉伯数字转中文* @Author faro_z* @Date 2022/12/5 18:07* @Version 1.0**/
public class NumStrConvertor {public static void main(String[] args) {int[] nums = {1000, 1024, 10, 100024, 92030003, 90000003, 1, 2, 3, 11};for (int num : nums) {System.out.println(cnNumConvertor(num));}}/*** 转换阿拉伯数字到中文字符** @param num* @return*/public static String cnNumConvertor(int num) {if (num==0) {return "零";}final String illegalPrefix = "一十";final String[] units = {"", "万", "亿", "兆"};String prefix = "";if (num < 0) {prefix = "负";num = -num;}String numStr = String.valueOf(num);final int metaLen = 4;int r = numStr.length() - 1;int l = Math.max(0, r - metaLen + 1);int unitIndex = 0;StringBuilder builder = new StringBuilder();while (r >= 0 && l >= 0) {builder.insert(0, cnNumMetaConvertor(numStr.substring(l, r + 1)) + units[unitIndex++]);r = l - 1;l = Math.max(0, r - metaLen + 1);}String res = builder.toString();if (res.startsWith(illegalPrefix)) {res = res.substring(1, res.length());}return prefix + res;}/*** 按照中文阅读习惯,处理最高4位的 meta 数字集** @param num* @return*/private static String cnNumMetaConvertor(String num) {final int metaLen = 4;final String zeroStr = "0";final String[] cnNums = {"零", "一", "二", "三", "四", "五", "六", "七", "八", "九"};final String[] units = {"千", "百", "十", ""};StringBuilder builder = new StringBuilder();int N = num.length();boolean canNotJudge = N > metaLen || (N < metaLen && num.startsWith(zeroStr));if (canNotJudge) {return "";}boolean isPreZero = false;int unitIndex = metaLen - num.length() - 1;for (int i = 0; i < N; i++) {++unitIndex;final int currNum = num.charAt(i) - '0';final String currNumCn = cnNums[currNum];final String currUnit = units[unitIndex];if (currNum == 0) {if (isPreZero) {continue;}isPreZero = true;builder.append(currNumCn);} else {isPreZero = false;builder.append(currNumCn);builder.append(currUnit);}}String res = builder.toString();return res.endsWith("零") ? res.substring(0, res.length() - 1) : res;}
}

3、思路讲解

按照中文阅读习惯,我们习惯将每四位分为一个单元做阅读,比如如下示例:

image-20221205223236630

因为每四位的处理逻辑都是一样的,所以这部分我们可以单独拆出来处理:

private static String cnNumMetaConvertor(String num) {final int metaLen = 4;final String zeroStr = "0";final String[] cnNums = {"零", "一", "二", "三", "四", "五", "六", "七", "八", "九"};final String[] units = {"千", "百", "十", ""};StringBuilder builder = new StringBuilder();int N = num.length();// 大于四位或者  小于四位,但是开头的数字为0,都不满足处理条件boolean canNotJudge = N > metaLen || (N < metaLen && num.startsWith(zeroStr));if (canNotJudge) {return "";}// 用来标识前一个字符是否为0,避免出现重复打印“零”的情况boolean isPreZero = false;int unitIndex = metaLen - num.length() - 1;for (int i = 0; i < N; i++) {++unitIndex;final int currNum = num.charAt(i) - '0';final String currNumCn = cnNums[currNum];final String currUnit = units[unitIndex];if (currNum == 0) {if (isPreZero) {continue;}isPreZero = true;builder.append(currNumCn);} else {isPreZero = false;builder.append(currNumCn);builder.append(currUnit);}}String res = builder.toString();return res.endsWith("零") ? res.substring(0, res.length() - 1) : res;}
}

接着,就是将“每个四位”进行拼接,并依次在后面加上,万、亿、兆的单位:

这里使用双指针法进行范围截取,以 4 为单位截取字符串,然后使用上面的函数处理

cnNumConvertor(num) {// 负数和非0判断// ...res=""while() {currSplit = split(num)currSplitCN = cnNumMetaConvertor(currSplit)res+= currSplitCN + 单位}// 特殊字符处理// ...return res
}

同时外层函数我们还要做个负数和0的判断

负数的话,要转换成正数处理,最后返回结果时加上"负"的前缀

0 直接返回 “零”

public static String cnNumConvertor(int num) {if (num==0) {return "零";}final String illegalPrefix = "一十";final String[] units = {"", "万", "亿", "兆"};String prefix = "";if (num < 0) {prefix = "负";num = -num;}String numStr = String.valueOf(num);final int metaLen = 4;int r = numStr.length() - 1;int l = Math.max(0, r - metaLen + 1);int unitIndex = 0;StringBuilder builder = new StringBuilder();while (r >= 0 && l >= 0) {builder.insert(0, cnNumMetaConvertor(numStr.substring(l, r + 1)) + units[unitIndex++]);r = l - 1;l = Math.max(0, r - metaLen + 1);}String res = builder.toString();// 对一十,一十万,一十四这类结果做处理if (res.startsWith(illegalPrefix)) {res = res.substring(1, res.length());}return prefix + res;}

特殊结果处理:

上述代码本身能完成很好的结果生成,但是还是有部分结果不满足中文阅读习惯

比如 对一十,一十万,一十四这类结果,只要将前缀的 “一” 去掉即可

if (res.startsWith(illegalPrefix)) {res = res.substring(1, res.length());
}

这篇关于【Java】阿拉伯数字转汉字(完全符合中文阅读习惯)(支持所有整数类型)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/295407

相关文章

Java中流式并行操作parallelStream的原理和使用方法

《Java中流式并行操作parallelStream的原理和使用方法》本文详细介绍了Java中的并行流(parallelStream)的原理、正确使用方法以及在实际业务中的应用案例,并指出在使用并行流... 目录Java中流式并行操作parallelStream0. 问题的产生1. 什么是parallelS

Java中Redisson 的原理深度解析

《Java中Redisson的原理深度解析》Redisson是一个高性能的Redis客户端,它通过将Redis数据结构映射为Java对象和分布式对象,实现了在Java应用中方便地使用Redis,本文... 目录前言一、核心设计理念二、核心架构与通信层1. 基于 Netty 的异步非阻塞通信2. 编解码器三、

SpringBoot基于注解实现数据库字段回填的完整方案

《SpringBoot基于注解实现数据库字段回填的完整方案》这篇文章主要为大家详细介绍了SpringBoot如何基于注解实现数据库字段回填的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以了解... 目录数据库表pom.XMLRelationFieldRelationFieldMapping基础的一些代

一篇文章彻底搞懂macOS如何决定java环境

《一篇文章彻底搞懂macOS如何决定java环境》MacOS作为一个功能强大的操作系统,为开发者提供了丰富的开发工具和框架,下面:本文主要介绍macOS如何决定java环境的相关资料,文中通过代码... 目录方法一:使用 which命令方法二:使用 Java_home工具(Apple 官方推荐)那问题来了,

Java HashMap的底层实现原理深度解析

《JavaHashMap的底层实现原理深度解析》HashMap基于数组+链表+红黑树结构,通过哈希算法和扩容机制优化性能,负载因子与树化阈值平衡效率,是Java开发必备的高效数据结构,本文给大家介绍... 目录一、概述:HashMap的宏观结构二、核心数据结构解析1. 数组(桶数组)2. 链表节点(Node

Java AOP面向切面编程的概念和实现方式

《JavaAOP面向切面编程的概念和实现方式》AOP是面向切面编程,通过动态代理将横切关注点(如日志、事务)与核心业务逻辑分离,提升代码复用性和可维护性,本文给大家介绍JavaAOP面向切面编程的概... 目录一、AOP 是什么?二、AOP 的核心概念与实现方式核心概念实现方式三、Spring AOP 的关

详解SpringBoot+Ehcache使用示例

《详解SpringBoot+Ehcache使用示例》本文介绍了SpringBoot中配置Ehcache、自定义get/set方式,并实际使用缓存的过程,文中通过示例代码介绍的非常详细,对大家的学习或者... 目录摘要概念内存与磁盘持久化存储:配置灵活性:编码示例引入依赖:配置ehcache.XML文件:配置

Java 虚拟线程的创建与使用深度解析

《Java虚拟线程的创建与使用深度解析》虚拟线程是Java19中以预览特性形式引入,Java21起正式发布的轻量级线程,本文给大家介绍Java虚拟线程的创建与使用,感兴趣的朋友一起看看吧... 目录一、虚拟线程简介1.1 什么是虚拟线程?1.2 为什么需要虚拟线程?二、虚拟线程与平台线程对比代码对比示例:三

Java中的.close()举例详解

《Java中的.close()举例详解》.close()方法只适用于通过window.open()打开的弹出窗口,对于浏览器的主窗口,如果没有得到用户允许是不能关闭的,:本文主要介绍Java中的.... 目录当你遇到以下三种情况时,一定要记得使用 .close():用法作用举例如何判断代码中的 input

Spring Gateway动态路由实现方案

《SpringGateway动态路由实现方案》本文主要介绍了SpringGateway动态路由实现方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随... 目录前沿何为路由RouteDefinitionRouteLocator工作流程动态路由实现尾巴前沿S