logo头像

学如逆水行舟,不进则退!!!

文章目录

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

本文于366天之前发表,文中内容可能已经过时。

[TOC]

阿拉伯数字肯定是使用最广泛的符合之一了。我们日常生活都离不开数字。中文下的数字是中国特色的数字。开发中也会遇到需要两者相互转换的需求。今天就来实现下。

中文数字转阿拉伯数字

  • 想上面的数字一样。假设我们的中文数字是【一亿七千七十九万七千一百九十七】。

解题思路

  • 首先我们需要将上面中文数字按阿拉伯数字进行分离。这里我们先提出一个思想前提: 亿、万 这种是高级单位;千、百、十这种是低级单位。所以我们先按高级单位将上面的进行拆分。

  • 我们得到上面的三个数字。分别是【一亿】、【七千零七十九万】、【七千一百九十七】。下面我们针对这三个数字进行翻译。

各个击破

  • 仔细分析下上面三个中文数字,不难得出结论-上面三个数字去掉高级单位剩下的都只有低级单位了。这也是我们实现的重点【低级单位内的数字转换】

  • 我们将三个数字分别转换完成之后,剩下的就是将他们组合。组合的问题也就是中间补零和去零的操作。

  • 【七千零七十九万】去掉高级单位【七千零七十九】我们翻译也很简单就是将低级单位去掉变成【七零七九】及【7079】。那么上面的三位数字分别是

中文数字 去掉单位后 数字映射
一亿 1
七千零七十九万 七零七九 7079
七千一百九十七 七一九七 7197
  • 三位数字翻译好之后我们进行阿拉伯数字的拼接就完成了。 170797197

友情提醒

  • 上面的数字翻译的很是顺利。但是又这么一类数字总是事与愿违。
  • 【一亿零七十九万零一百九十七】==【100790197】
  • 按照上面的思路我们会有如有推理
中文数字 去掉单位后 数字映射
一亿 1
零七十九万 零七九 079
零一百九十七 零一九七 0197
  • 根据表格我们拼接得到的数字是【10790197】。这个时候问题就大了去了。我们丢失了一位0。原因也很简单在中文数字中在同一高级单位维度里连续多个零的出现会同一读零。但是阿拉伯数字中确实实实在在的占位的。所以这里就会缺失一位零。
  • 这里的情况是一开始笔者没哟注意到的。但是后来改正了。所以上面提到的合并方法是没有问题的。上面是进行数字化乘以10000的。所以这里的0也不会丢失的。
  • 正确的拼接方案是 ((110000)+079)10000+0197=100790197

  • 这种问题反向过来同样值得注意,在阿拉伯转中文数字的时候我们需要注意0到底代表几个0

阿拉伯数字转中文数字

  • 【100790197】 ==【一亿零七十九万零一百九十七】
  • 【100000197】 ==【一亿零一百九十七】

  • 下面我们将对上面的两个阿拉伯数字进行解析转换。同样我们对他们进行高位分离。这里需要注意的是我们需要从低位到高位方向进行分离

  • 分离是从低位到高位。但是我们转换却要从高位到低位。顺序不能错。在我们阿拉伯数字转中文数字的时候非零数字注解映射转换就行了。但是遇到0的时候我们需要有一下三个条件才能转换,否则就要忽略。

    • 第一次遇到0
    • 数字为0
    • 统一高位单元内后面并不是全是0
  • 简单解释下上面三个。第一个通过一个状态为就能搞定。第二个其实就是保险点。可有可无。最重要第三点遇零后后面不能全是0.这个时候我们才可以将当前位置0翻译成零。

  • 每个非零数字翻译后需要加上低级单位的。
  • 所以上面的0079我们翻译的是【零七十九】
  • 但是零七九并不是真正的汉字数字。所以我们在每一次高位翻译完成之后需要加上高位单位。所以【0079】==【零七十九万】
  • 所以我们得出如下
阿拉伯数字 数字映射
1 一亿
0079 零七十九万
0197 零一百九十七
  • 所以【100790197】 ==【一亿零七十九万零一百九十七】
阿拉伯数字 数字映射
1 一亿
0000
0197 零一百九十七
  • 在加入高级单位时我们需要判断高级单位内数字是否有效。因为我们上面三个原因。所以0000对应的中文数字就是空字符串。这里我们认为是无效中文数字。所以万单位也就没有了。所以【100000197】==【一亿零一百九十七】

测试

  • 光谈理论不讲实践都是扯淡。下面我们需要对我们的设计进行验证。如何验证嗯。好在我们实现的【中文数字转阿拉伯数字】、【阿拉伯数字转中文数字】 。 那么我们直接通过两个方法相互转换。看看最终是不是原来的数据就能验证出来了。话不多说、上代码

Integer right = 0;
Integer total = 10000000;
List<Map<String, Object>> list = new ArrayList<>();
for (int i = 0; i < total; i++) {
    Integer number = MathUtil.getInstance().getRandom(1, 1000000000);
    //System.out.println(i);
    //Integer number = 400001989;
    String chinese = DigitUtil.getInstance().getNumberFromAlabo(number.toString());
    String alabo = DigitUtil.getInstance().getNumberFromChinese(chinese);
    boolean equals = alabo.equals(number.toString());
    if (equals) {
        right++;
    } else {
        Map<String, Object> map  = new HashMap<>();
        map.put("number", number);
        map.put("alabo", alabo);
        map.put("chinese", chinese);
        list.add(map);
    }
}
for (Map<String, Object> map : list) {
    System.out.println(map);
}
System.out.println("成功率:"+Double.valueOf(right/(double)total));
  • 测试后的正确率是1 。 也就是0差错。
  • 欢迎指出错误。

源码


package org.zxhtom.utils;

import org.zxhtom.constant.ChineseNumber;

import java.util.*;

/**
 * @package org.zxhtom.utils
 * @Class DigitUtil
 * @Description 数字工具类
 * @Author zhangxinhua
 * @Date 19-7-2 下午3:47
 */
public class DigitUtil {
    private static DigitUtil util;

    public static DigitUtil getInstance() {
        if (null == util) {
            util = new DigitUtil();
        }
        return util;
    }

    /**
     * 中文数字转阿拉伯数字
     *  一万两千三百五十四 --> 12354
     * @param chinese 阿拉伯数字
     * @return 中文数字
     */
    public String getNumberFromChinese(String chinese) {
        String result = "0";
        //将中文数字按四位进行截取。这样每一位里只有单一
        List<String> lists = new ArrayList<>();
        //暂时未使用到
        int lastLevelIndex = 0;
        //循环遍历,目的是将亿万进行分离
        for (int i =  ChineseNumber.highLevel.size()-1; i>=0; i--) {
            //判断亿万单位出现索引
            int levelIndex = chinese.indexOf(ChineseNumber.highLevel.get(i));
            if (levelIndex>0) {
                //表示有单位索引 , 将单位前数据进行截取装入lists中。后面的继续循环截取
                lists.add(chinese.substring(0, levelIndex));
                chinese = chinese.substring(levelIndex+1);
            } else if (levelIndex == -1) {
                //表示已经是最低单位了,不超过万。直接加入lists中 , 这里情况对应的是高位分离后,次高位开头是0的情况
                lists.add(ChineseNumber.number.get(0));
            } else if (levelIndex == 0) {
                while (levelIndex > 1) {
                    levelIndex--;
                    lists.add(ChineseNumber.number.get(0));
                }
                //直接加入
                lists.add(chinese);
            }
        }
        //针对分离的四位数据,进行单独翻译
        for (int i = 0; i < lists.size(); i++) {
            //未使用
            Integer highLevelIndex = lists.size() - i - 1;
            //获取单元数据
            String single = lists.get(i);
            //对单元数据进行翻译 。
            String nextResult = getNumberFromFChinese(single);
            //lists中每位都是4位数截取 ,所以这里需要乘以10000进行叠加
            Long next = Long.valueOf(Integer.valueOf(result) * (int)(Math.pow(10, 4)) + Integer.valueOf(nextResult));
            result = next.toString();
        }
        //将开头0抹掉
        result = result.replaceFirst("^(0+)", "");
        return result;
    }

    /**
     * 通过中文数字获取4位数阿拉伯数字
     * 万以内的数据转换
     * @param single
     * @return
     */
    private String getNumberFromFChinese(String single) {
        String result = "0";
        Integer highIndex = 1;
        for (int i = 0; i < single.length(); i++) {
            String str = String.valueOf(single.charAt(i));
            int unit = ChineseNumber.level.indexOf(str);
            int number = ChineseNumber.number.indexOf(str);
            if (unit == -1) {
                //当前数字是万以内的单位即  千百十其中之一
                int next = 0;
                if (i < single.length() - 1) {
                    //如果不是最后一位,则需要考虑当前位的权重
                    next = ChineseNumber.level.indexOf(String.valueOf(single.charAt(i + 1)));
                }
                result=String.valueOf(Integer.valueOf(result)+number * (int) (Math.pow(10, next)));
            }
        }
        //权重叠加
        result = ""+Integer.valueOf(result) * (int) (Math.pow(10, highIndex - 1));
        return result;
    }

    /**
     * 阿拉伯数字转中文数字
     * 12354 --> 一万两千三百五十四
     * @param alabo 阿拉伯数字
     * @return 中文数字
     */
    public String getNumberFromAlabo(String alabo) {
        String result = "";
        List<String> list = new ArrayList<>();
        for (int length = alabo.length()-1; length >= 0; length--) {
            list.add(String.valueOf(alabo.charAt(length)));
        }
        List<List<String>> lists = CollectionUtil.averageSize(list, 4);
        Collections.reverse(lists);
        if (CollectionUtil.isNotEmpty(lists)) {
            for (int index=0;index<lists.size();index++) {
                List<String> singleNumList = lists.get(index);
                //反转集合
                Collections.reverse(singleNumList);
                //默认0 false
                Boolean zeroflag =false;
                String chinese = "";
                for (int j=0 ; j<singleNumList.size();j++) {
                    Integer number = Integer.valueOf(singleNumList.get(j));
                    if (number == 0 && !zeroflag && afterNotAllZero(singleNumList, j)) {
                        //第一次遇到0 且后面有小单位内并不是全为0
                        chinese += ChineseNumber.number.get(number);
                        //修改遇零状态true
                        zeroflag = true;
                    } else if(number!=0) {
                        //映射出对应的中文数字
                        chinese += ChineseNumber.number.get(number) + ChineseNumber.level.get(singleNumList.size()-j-1);
                    }
                }
                if (index==lists.size()&&chinese.substring(0, 1).equals(ChineseNumber.number.get(0))) {
                    //条件永远不成立。
                    chinese = chinese.substring(1);
                }
                //并不是全部为0,该高级单位才会生效
                if (chinese.length()>0&&!ChineseNumber.highLevel.contains(chinese.substring(chinese.length() - 1))) {
                    result += chinese + ChineseNumber.highLevel.get(lists.size() - 1 - index);
                }
            }
        }
        return result;
    }

    /**
     * 判断singleNumList在j位置之后是否全是0
     * @param singleNumList
     * @param j
     * @return
     */
    private boolean afterNotAllZero(List<String> singleNumList, int j) {
        for (int i = j+1; i < singleNumList.size(); i++) {
            if (!"0".equals(singleNumList.get(i))) {
                return true;
            }
        }
        return false;
    }

    public static void main(String[] args) {
        Integer right = 0;
        Integer total = 10000000;
        List<Map<String, Object>> list = new ArrayList<>();
        for (int i = 0; i < total; i++) {
            Integer number = MathUtil.getInstance().getRandom(1, 1000000000);
            //System.out.println(i);
            //Integer number = 400001989;
            String chinese = DigitUtil.getInstance().getNumberFromAlabo(number.toString());
            String alabo = DigitUtil.getInstance().getNumberFromChinese(chinese);
            boolean equals = alabo.equals(number.toString());
            if (equals) {
                right++;
            } else {
                Map<String, Object> map  = new HashMap<>();
                map.put("number", number);
                map.put("alabo", alabo);
                map.put("chinese", chinese);
                list.add(map);
            }
        }
        for (Map<String, Object> map : list) {
            System.out.println(map);
        }
        System.out.println("成功率:"+Double.valueOf(right/(double)total));
    }
}

加入战队

# 加入战队

微信公众号

微信公众号

上一篇
坚持原创技术分享,您的支持将鼓励我继续创作!

评论系统未开启,无法评论!