阿拉伯数字与中文数字的转换----------相互转化
今天继续看《算法的乐趣》,学习了阿拉伯数字与中文数字的转化。
汉字用零一二三四五六七八九作为基本计数,与阿拉伯数字靠数字偏移位置的权位不一样。中文数字是才有“数字+权位”的方式组成数字,比方百,千,万。
中文数字每一个数字后都会跟上一个权位。权位就是数字的量值,相当于阿拉伯数字的数位。
中文计数以万为小节,万下面没有节权,万之上是亿为节权。
中文另一个特点是多变的“零”,大概总结为三个规则:
1.以10000为小节。小节的结尾即使是0,也不使用“零”。
2.小节内两个非0数字之间要使用“零”。
3.当小节的“千”位是0时,若本小节的前一小节无其它数字。则不用“零”,否则就要用“零”。
算法设计:
首先定义三个字符串数组,存放数字位、节权位、权位
然后再分两个方法实现,一个实现节权的操作处理,另一个实现小节内的操作。
第二个程序是实现中文数字转化为阿拉伯数字,这个我看不懂书上的一小部分代码。可是我读懂了作者的思想。所以我自己写了一个与书上不一样的算法出来,可是思想是一样的。
都是通过节权处分里小节,然后逐个小节计算,然后再合并得到结果。
以下是我的代码:
</pre><pre name="code" class="java">package 阿拉伯数字与中文数字; public class Main { public static void main(String[] args) { Main ma = new Main(); Tool to = new Tool(); ma.initMain(); } public void initMain(){ testNumberToChinese(); System.out.println("————————————————————————————————————————"); testChineseToNumber(); } public void testNumberToChinese(){ NumberChangeToChinese numToChinese = new NumberChangeToChinese(); System.out.println("0:"+numToChinese.numberToChinese(0)); System.out.println("1:"+numToChinese.numberToChinese(1)); System.out.println("2:"+numToChinese.numberToChinese(2)); System.out.println("3:"+numToChinese.numberToChinese(3)); System.out.println("4:"+numToChinese.numberToChinese(4)); System.out.println("5:"+numToChinese.numberToChinese(5)); System.out.println("6:"+numToChinese.numberToChinese(6)); System.out.println("7:"+numToChinese.numberToChinese(7)); System.out.println("8:"+numToChinese.numberToChinese(8)); System.out.println("9:"+numToChinese.numberToChinese(9)); System.out.println("10:"+numToChinese.numberToChinese(10)); System.out.println("11:"+numToChinese.numberToChinese(11)); System.out.println("110:"+numToChinese.numberToChinese(110)); System.out.println("111:"+numToChinese.numberToChinese(111)); System.out.println("100:"+numToChinese.numberToChinese(100)); System.out.println("102:"+numToChinese.numberToChinese(102)); System.out.println("1020:"+numToChinese.numberToChinese(1020)); System.out.println("1001:"+numToChinese.numberToChinese(1001)); System.out.println("1015:"+numToChinese.numberToChinese(1015)); System.out.println("1000:"+numToChinese.numberToChinese(1000)); System.out.println("10000:"+numToChinese.numberToChinese(10000)); System.out.println("20010"+numToChinese.numberToChinese(20010)); System.out.println("20001"+numToChinese.numberToChinese(20001)); System.out.println("100000:"+numToChinese.numberToChinese(100000)); System.out.println("1000000:"+numToChinese.numberToChinese(1000000)); System.out.println("10000000"+numToChinese.numberToChinese(10000000)); System.out.println("100000000:"+numToChinese.numberToChinese(100000000)); System.out.println("1000000000"+numToChinese.numberToChinese(1000000000)); System.out.println("2000105"+numToChinese.numberToChinese(2000105)); System.out.println("20001007:"+numToChinese.numberToChinese(20001007)); System.out.println("2005010010:"+numToChinese.numberToChinese(2005010010)); } public void testChineseToNumber(){ ChineseChangeToNumber chineseToNumber = new ChineseChangeToNumber(); System.out.println("二十亿零五千五百零一万四千零一十:"+chineseToNumber.ChineseToNumber("二十亿零五千五百零一万四千零一十")); System.out.println("二千万一千零七:"+chineseToNumber.ChineseToNumber("二千万一千零七")); System.out.println("二万零一:"+chineseToNumber.ChineseToNumber("二万零一")); System.out.println("二万零一十:"+chineseToNumber.ChineseToNumber("二万零一十")); System.out.println("一万:"+chineseToNumber.ChineseToNumber("一万")); System.out.println("一千零一十五:"+chineseToNumber.ChineseToNumber("一千零一十五")); System.out.println("一千:"+chineseToNumber.ChineseToNumber("一千")); System.out.println("一亿:"+chineseToNumber.ChineseToNumber("一亿")); } }
这是主类,用于启动程序和測试。
package 阿拉伯数字与中文数字; public class NumberChangeToChinese { public String numberToChinese(int num){//转化一个阿拉伯数字为中文字符串 if(num == 0){ return "零"; } int unitPos = 0;//节权位标识 String All = new String(); String chineseNum = new String();//中文数字字符串 boolean needZero = false;//下一小结是否须要补零 String strIns = new String(); while(num>0){ int section = num%10000;//取最后面的那一个小节 if(needZero){//推断上一小节千位是否为零。为零就要加上零 All = Tool.chnNumChar[0] + All; } chineseNum = sectionTOChinese(section,chineseNum);//处理当前小节的数字,然后用chineseNum记录当前小节数字 if( section!=0 ){//此处用if else 选择语句来运行加节权位 strIns = Tool.chnUnitSection[unitPos];//当小节不为0。就加上节权位 chineseNum = chineseNum + strIns; }else{ strIns = Tool.chnUnitSection[0];//否则不用加 chineseNum = strIns + chineseNum; } All = chineseNum+All; chineseNum = ""; needZero = (section<1000) && (section>0); num = num/10000; unitPos++; } return All; } public String sectionTOChinese(int section,String chineseNum){ String setionChinese = new String();//小节部分用独立函数操作 int unitPos = 0;//小节内部的权值计数器 boolean zero = true;//小节内部的制零推断。每一个小节内仅仅能出现一个零 while(section>0){ int v = section%10;//取当前最末位的值 if(v == 0){ if( !zero ){ zero = true;//须要补零的操作。确保对连续多个零仅仅是输出一个 chineseNum = Tool.chnNumChar[0] + chineseNum; } }else{ zero = false;//有非零的数字。就把制零开关打开 setionChinese = Tool.chnNumChar[v];//相应中文数字位 setionChinese = setionChinese + Tool.chnUnitChar[unitPos];//相应中文权位 chineseNum = setionChinese + chineseNum; } unitPos++; section = section/10; } return chineseNum; } }
这第二个是阿拉伯数字转化成中文数字的类,实现的过程大致跟书上的一样。
以下是第三个中文转化成阿拉伯数组的类:
package 阿拉伯数字与中文数字; public class ChineseChangeToNumber { public int ChineseToNumber(String str){ String str1 = new String(); String str2 = new String(); String str3 = new String(); int k = 0; boolean dealflag = true; for(int i=0;i<str.length();i++){//先把字符串中的“零”除去 if('零' == (str.charAt(i))){ str = str.substring(0, i) + str.substring(i+1); } } String chineseNum = str; for(int i=0;i<chineseNum.length();i++){ if(chineseNum.charAt(i) == '亿'){ str1 = chineseNum.substring(0,i);//截取亿前面的数字,逐个对比表格。然后转换 k = i+1; dealflag = false;//已经处理 } if(chineseNum.charAt(i) == '万'){ str2 = chineseNum.substring(k,i); str3 = str.substring(i+1); dealflag = false;//已经处理 } } if(dealflag){//假设没有处理 str3 = chineseNum; } int result = sectionChinese(str1) * 100000000 + sectionChinese(str2) * 10000 + sectionChinese(str3); return result; } public int sectionChinese(String str){ int value = 0; int sectionNum = 0; for(int i=0;i<str.length();i++){ int v = (int) Tool.intList.get(str.charAt(i)); if( v == 10 || v == 100 || v == 1000 ){//假设数值是权位则相乘 sectionNum = v * sectionNum; value = value + sectionNum; }else if(i == str.length()-1){ value = value + v; }else{ sectionNum = v; } } return value; } }
这真真正正是我自己一个个字写的,都是通过思考得出的结果,可能有些不严谨,可是确实能够实现。
第四个是工具类,存放字符串数据用的。
package 阿拉伯数字与中文数字; import java.util.ArrayList; import java.util.HashMap; import java.util.Set; public class Tool { //数字位 public static String[] chnNumChar = {"零","一","二","三","四","五","六","七","八","九"}; public static char[] chnNumChinese = {'零','一','二','三','四','五','六','七','八','九'}; //节权位 public static String[] chnUnitSection = {"","万","亿","万亿"}; //权位 public static String[] chnUnitChar = {"","十","百","千"}; public static HashMap intList = new HashMap(); static{ for(int i=0;i<chnNumChar.length;i++){ intList.put(chnNumChinese[i], i); } intList.put('十',10); intList.put('百',100); intList.put('千', 1000); } }
以下的图片是我的測试结果:
第一幅图是阿拉伯数字转化成中文:
第二张图片是中文数字转化成阿拉伯数字的:
这个数字转化算法,我看了几个小时才看懂一点点,然后在编程的时候,遇到了诸多问题,可是我最后都是独自一个个攻克了,没有问别人,遇到了一些基本数据类型的问题,比方int型不能超过21亿。" "两个点的是字符串类型,' '一个点的是字符类型。这个问题我在传入HashMap队列中的时候就卡得我非常烦躁,传入的字符串类型。然后用字符串的CharAt()去调用,结果当然是出现异常错误。无法编译了。
还实用了一个没有必要的二重循环去检測,事实上没有必要,队列有现成的方法让我去用。二重循环中还出现了死循环。在第二重里写错成了i++(事实上应该是j++),导致循环不断。
算法学习之路不易,可是贵在坚持,我在编程这几个小时里经常想不出解决方式。遇到bug无法解决,可是又没有人问。
可是没关系,我坚持了下来,攻克了我遇到的一切问题。在算法这条路上再前进了一小步,我相信我以后的IT之路一定能够越走越远,越走越宽。