1 /* 2 * 程序目的: 从命令行输入一个数,并将其转化为中文金额的大写方式 3 * 思路: 4 * 所需对象:用到两个数组,一个存中文大写的数字,一个存金额单位; 5 * 为了保持精度的相对准确,用到BigDecimal类;(不懂的朋友,上网一查就知道了); 6 * 我这里用了StringBuilder类来存转化后的结果;(其实用String,StringBuffer都可以) 7 * 过程:输入一个double类型的数———>转化为BigDecimal类的对象———>四舍五入后转化为long类型的数; 8 * 先判断一下小数部分出现的特殊情况; 9 * 统一处理数字;(每次取一位【用%10的方法】,通过和预先设置好的数组对应的方式来填充数据) 10 * 输出最终的结果; 11 * 难点:就零的处理; 12 * 13 * 1、阿拉伯数字中间有“0”时,中文大写要写“零”字,如¥1409.50应写成人民币壹仟肆佰零玖元伍角; 14 2、阿拉伯数字中间连续有几个“0”时、中文大写金额中间可以只写一个“零”字,如¥6007.14应写成人民币陆仟零柒元壹角肆分。 15 3、阿拉伯金额数字万位和元位是“0”,或者数字中间连续有几个“0”,万位、元位也是“0”但千位、角位不是“0”时,中文大写金额中可以只写一个零字(我这这里用的就是这种),也 可以不写“零”字,如¥1680.32应写成人民币壹仟陆佰捌拾元零叁角贰分,或者写成人民币壹仟陆佰捌拾元叁角贰分。又如¥107000.53应写成人民币壹拾万柒仟元零伍角叁分,或 者写成人民币壹拾万零柒仟元伍角叁分。 16 4、阿拉伯金额数字角位是“0”而分位不是“0”时,中文大写金额“元”后面应写“零”字,如¥16409.02应写成人民币壹万陆仟肆佰零玖元零贰分,又如¥325.04应写成人民币叁佰贰拾 伍元零肆分。 17 * 18 * 方法:分情况处理; 19 * 注:其实可以更加简洁写,但是为了看的更清楚,更加具有良好的编程习惯;故有些写的“啰嗦”,请见谅! 20 * 若发现我的程序有不妥之处,还望评论指正,共同学习; 21 */ 22 23 import java.math.BigDecimal; 24 import java.util.Scanner; 25 26 public class NumToCn { 27 28 //这里使用String, StringBuffer其实都可以;但从可变长度和单线程方面考虑,StringBuilder较为合适; 29 private static StringBuilder sb = new StringBuilder(); 30 31 private static final String[] CN_NUMBER = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"}; 32 private static final String[] CN_UNIT = { "分", "角", "圆","拾", "佰", "仟", "万", "拾", "佰", "仟", "亿", "拾", "佰", "仟", "兆", "拾", "佰", "仟", "顺" }; 33 34 //一些额外附加的字符 35 private static final String CN_NEGATIVE = "负"; 36 private static final String CN_FULL = "整"; 37 private static final String CN_ZERO_FULL = "零圆整"; 38 private static final int PERCISION = 2; // 精度 39 40 public static String numToCn (BigDecimal numOfMoney) { 41 42 //当此 BigDecimal 的值为负、零或正时,返回 -1、0 或 1。 43 int signum = numOfMoney.signum(); 44 45 //若输入为0,输出零圆整; 46 if(signum == 0) { 47 return CN_ZERO_FULL; 48 } 49 50 //对金额进行四舍五入转化为long类型的整数;先将数的小数点向右移两位,然后在四舍五入,取绝对值,最后将它转换为长整型; 51 long number = numOfMoney.movePointRight(PERCISION).setScale(0, BigDecimal.ROUND_HALF_UP).abs().longValue(); 52 int numIndex = 0; //记录数字的个数; 53 boolean getZero = false; 54 /* 55 * 思路:要先判断一下小数部分的具体情况;究其根本是因为:小数部分和整数部分在处理“0”的问题上略有不同;避免出现如图1所示的情况; 56 */ 57 //得到小数部分(小数点后两位); 58 long scale = number % 100; 59 if(scale == 0) { //若小数部分为"00"时的情况;骚年,不要忘了在最后追加特殊字符:整 60 numIndex += 2; 61 getZero = true; 62 number /= 100; // 从number去掉为0数; 63 sb.append(CN_FULL); 64 } else if(scale % 10 == 0){ //若小数部分为"*0"时的情况; 65 numIndex += 1; 66 getZero = true; 67 number /= 10;// 从number去掉为0数; 68 } 69 70 //排除上述两种小数部分的特殊情况,则对小数和整数的处理就是一样一样一样地了! 71 while(true) { 72 //循环结束条件; 73 if(number <= 0){ 74 break; 75 } 76 77 //每次通过取余来得到最后一位数; 78 int numUnit = (int)(number % 10); 79 if(numUnit != 0){ 80 sb.insert(0, CN_UNIT[numIndex]); //先添加单位 81 sb.insert(0, CN_NUMBER[numUnit]); //在添加根据数字值来对应数组中的中文表述; 82 getZero = false; //表明当前数不是0; 83 } 84 else { 85 //意思是它的上一次的数不是零,那么打印出零; 86 if(!getZero) { 87 sb.insert(0, CN_NUMBER[numUnit]); 88 } 89 //若角分位为零,那么打印零; 90 if(numIndex == 2) { 91 if(number > 0) { 92 sb.insert(0, CN_UNIT[numIndex]); 93 } 94 } else if((numIndex - 2) % 4 == 0 && number % 1000 !=0 ) { //第一个条件是为了每隔4位,打印“圆,万,亿”;第二个条件是为了避免出现如图3的情况; 95 sb.insert(0, CN_UNIT[numIndex]); 96 } 97 getZero = true; //将其置为true,那么如果下一位还是0,也不会再打印一遍'零';避免出现图2的情况; 98 } 99 100 // 从number每次都去掉最后一个数 101 number = number / 10; 102 numIndex++; 103 } 104 105 // 如果signum == -1,则说明输入的数字为负数,就在最前面追加特殊字符:负 106 if(signum == -1) { 107 sb.insert(0, CN_NEGATIVE); 108 } 109 110 return sb.toString(); 111 } 112 113 114 public static void main(String[] args) { 115 Scanner scan = new Scanner(System.in); 116 double money = scan.nextDouble(); 117 BigDecimal numOfMoney = new BigDecimal(money); 118 String s = NumToCn.numToCn(numOfMoney); 119 System.out.println(s); 120 } 121 122 }
图一:
图二:
图三:上边数是100000000;因为是测试时用的,所以会是图中所示,不用纠结;