MyException - 我的异常网
当前位置:我的异常网» 编程 » 人民币金额小写变换大写

人民币金额小写变换大写

www.MyException.Cn  网友分享于:2013-08-27  浏览:180次
人民币金额小写转换大写

     准备跳槽,找了网上的笔试题看了一下, 发现常考金额转换成大写的编程题。

网上给出的答案不太满意,iteye上搜索一下, 有不少人给出一些例子,很多转换结果不准确,还有人说不到30行代码就能完成,我一看代码,天书而已, 立马摒弃掉了。
     思考一番, 也写了下代码,测试也没问题,有兴趣的朋友可以提提意见。

 

 

     网上其他人的代码大多是只能转换整数最多13位,一般转换方案都是下面两种(第一种看完都不想再当码农了 ,第二种看似挺好, 但是处理起来截取字符串麻烦,容易因规则太复杂找不到出路):

String capUnit[] = {'万','亿','万','圆',''};     
String capDigit[][] = { {''},{''},{'角','分',''},{''} {'仟','佰','拾',''}};     
String capNum[]={'零','壹','贰','叁','肆','伍','陆','柒','捌','玖'};     
 
String big = "壹贰叁肆伍陆柒捌玖";
String digit = new Array("圆拾佰仟万拾佰仟亿拾佰仟万","角分");

 

  
   我自己写的代码方案与第一种差不多,思路绝对清晰明了,代码里写得很清楚:

  

package com.liany.demo.translate;

import java.math.BigDecimal;
import java.text.DecimalFormat;

/**
 * 金额转换成大写
 * @author modiliany
 * @date 2012-04-10
 */
public class TransformMoney {
	
/*
以下摘自百度百科:http://baike.baidu.com/view/359995.htm
大写数字规则
	中文大写金额数字应用正楷或行书填写,如壹、贰、叁、肆、伍、陆、柒、捌、玖、拾、佰、仟、万、亿、元、角、分、零、整(正)等字样。不得用一、二(两)、三、四、五、六、七、八、九、十、廿、毛、另(或0)填写,不得自造简化字。如果金额数字书写中使用繁体字,如贰、陆、亿、万、圆的,也可。
	中文大写金额数字到"元"为止的,在"元"之后,应写"整"(或"正")字,在"角"之后,可以不写"整"(或"正")字。大写金额数字有"分"的,"分"后面不写"整"(或"正")字。
	中文大写金额数字前应标明"人民币"字样,大写金额数字有"分"的,"分"后面不写"整"(或"正")字。
	中文大写金额数字前应标明"人民币"字样,大写金额数字应紧接"人民币"字样填写,不得留有空白。大写金额数字前未印"人民币"字样的,应加填"人民币"三字。在票据和结算凭证大写金额栏内不得预印固定的"仟、佰、拾、万、仟、佰、拾、元、角、分"字样。
	阿拉伯数字小写金额数字中有"0"时,中文大写应按照汉语语言规律、金额数字构成和防止涂改的要求进行书写。举例如下:
	阿拉伯数字中间有"0"时,中文大写要写"零"字,如¥1409.50,应写成人民币壹仟肆佰零玖元伍角。
	阿拉伯数字中间连续有几个"0"时,中文大写金额中间可以只写一个"零"字,如¥6007.14,应写成人民币陆仟零柒元壹角肆分。
	阿拉伯金额数字万位和元位是"0",或者数字中间连续有几个"0",万位、元位也是"0",但千位、角位不是"0"时,中文大写金额中可以只写一个零字,也可以不写"零"字。如¥1680.32,应写成人民币壹仟陆佰捌拾元零叁角贰分,或者写成人民币壹仟陆佰捌拾元叁角贰分,又如¥107000.53,应写成人民币壹拾万柒仟元零伍角叁分,或者写成人民币壹拾万零柒仟元伍角叁分。
	阿拉伯金额数字角位是"0",而分位不是"0"时,中文大写金额"元"后面应写"零"字。如¥16409.02,应写成人民币壹万陆仟肆佰零玖元零贰分;又如¥325.04,应写成人民币叁佰贰拾伍元零肆分。 
*/
	
	static final String big = "零壹贰叁肆伍陆柒捌玖";		//大写
	static final String[] units = {"仟佰拾", "角分"};	//单位

	
	/**
	 * 双精度浮点数转换成字符串
	 * 注:
	 * 1、如果直接用String.toString(double d)方法,超大数额会出现科学计数法的字符串;
	 * 2、如果整数部分超过15位数,低位部分可能出现误差,所以不支持超过15位整数的数值,
	 *   一般数据库设计金额字段时都不会超过15位整数,如oracle用Number(18,3)的类型表示,整数部分最多15位,小数点后保留3位有效数字。
	 */
	public static String getDecimalStr(double d){
		//设置小数点后的精度,保留两位
		/*四舍五入结果参考:
		0.005,//0.01入
		0.015,//0.01舍
		0.025,//0.03入
		0.035,//0.04入
		0.045,//0.04舍
		0.055,//0.06入(前一位是5则入)
		*/
		String str = new BigDecimal(d).setScale(2, BigDecimal.ROUND_HALF_UP).toString();
		
		/*
		//经过测试,以下三种方法都是可以用的:
		//或1:
		String str = new BigDecimal(d).setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString();

		//或2:
		DecimalFormat format = new DecimalFormat();
		format.applyPattern("#################0.00");
		String str = format.format(d);
		
		//或3:
		DecimalFormat decimalFormat = new DecimalFormat();  
		decimalFormat.setMinimumFractionDigits(2);  
		decimalFormat.setMaximumFractionDigits(2);  
		decimalFormat.setGroupingUsed(false);  
		decimalFormat.setMaximumIntegerDigits(15);  
		decimalFormat.setMinimumIntegerDigits(15);  
		str=decimalFormat.format(d); 
		*/
		
		//如果结果是整数,则去掉尾巴
		if(str.endsWith(".00")){
			str = str.replace(".00", "");
		}
		return str;
	}
	
	/**
	 * 金额是double类型的要先转换成字符串
	 * @param money 金额
	 */
	public static String transform(double money){
		String moneyStr = getDecimalStr(money);
		return transform(moneyStr);
	}
	
	/**
	 * 金额转换成大字
	 * 我的思路:
	 * 1、double数值转换成数值字符串
	 * 2、处理整数部分:
	 *   填充到16位,不足16位则前面补'0',然后右起分成四组,每组根据"x仟x佰x拾x"的规则转换成大写,若该组为"0000"则结果是"零";
	 *   对这四组结果从高位到低位拼接起来,规则:[组4]万[组3]亿[组2]万[组1]圆。
	 * 3、处理小数部分(不多说)
	 */
	public static String transform(String moneyStr){
		String[] parts = moneyStr.split("\\.");	//区别整数、小数部分
		String result = "";
		
		//处理整数部分
		int length = parts[0].length();	//整数部分的位数
		if(length>15){
			return "金额太大,不能处理整数部分超过15位的金额!";
		}
		String intPart = parts[0];
		
		//填充到16位,因为是分4组,每组4个数字
		while(intPart.length()<16){
			intPart = '0' + intPart;
		}
		//共分四组,右起四位一组,例如:0001,2003,0030,3400
		String[] groups = new String[4]; 
		for(int i=0; i < groups.length; i++){
			int start = intPart.length()-(i+1)*4;	//开始位置
			int end = intPart.length()-i*4;			//结束位置
			groups[i] = intPart.substring(start, end);
			groups[i] = transformGroup(groups[i]);	//当前组的四位数字转换成大写
		}
		
		//对这四组结果从高位到低位拼接起来,规则:[组4]万[组3]亿[组2]万[组1]圆
		for(int i=groups.length-1; i>=0; i--){
			if(i==3){	//第四组:万亿级
				if(!"零".equals(groups[i])){
					result += groups[i] + "万";
				}
			}else if(i==2){	//第三组:亿级
				if(!"零".equals(groups[i])){
					result += groups[i] + "亿";
				}else{
					if(result.length()>0){
						result += "亿";
					}
				}
			}else if(i==1){	//第二组:万级
				if(!"零".equals(groups[i])){
					result += groups[i] + "万";
				}else if(!groups[i].startsWith("零")){
					result += groups[i];
				} 
			}else{	//第一组:千级
				if(!"零".equals(groups[i]) || result.length()==0){
					result += groups[i];
				}
				result += "圆";
			}
		}
		if(!"零圆".equals(result) && result.startsWith("零")){
			result = result.substring(1, result.length()); //最前面的可能出现的“零”去掉
		}

		//处理小数部分
		if(parts.length==2){
			String decimalPart = parts[1];	//小数部分
			for(int i=0; i < decimalPart.length();i++){
				int num = Integer.valueOf(decimalPart.charAt(i) + "");	//提取数字,左起
				result += big.charAt(num) + "" + units[1].charAt(i);	//数字变大写加上单位
			}
			result = result.replace("零角", "零");	//去掉"零角"的"角"
			result = result.replace("零分", "");	//去掉"零分"
		}else{
			result += "整";	//没有小数部分,则加上“整”
		}
		
		return result;
	}
	
	/**
	 * 处理整数部分的组,右起每四位是一组
	 * @param group 四位数字字符串
	 */
	public static String transformGroup(String group){
		String result = "";
		int length = group.length();
		for(int i=0; i < length; i++){
			int digit = Integer.valueOf(group.charAt(i)+"");	//单个数字,左起
			String unit = "";	//单位
			if(i!=length-1){
				unit = units[0].charAt(i) + "";	
			}
			result += big.charAt(digit) + unit; //数字变大写加上单位
		}
		
		result = result.replace("零仟", "零");
		result = result.replace("零佰", "零");
		result = result.replace("零拾", "零");
		
		while(result.contains("零零")){
			result = result.replace("零零", "零");	//如果有“零零”则变成一个“零”
		}
		
		if(!"零".equals(result) && result.endsWith("零")){
			result = result.substring(0, result.length()-1); //最未尾的可能出现的“零”去掉
		}
		return result;
	}


	/**
	 * @param args
	 */
	public static void main(String[] args) {
		double[] testData = {
			//测试数据一
			0,
			1,
			10,
			100,
			1000,
			10000,
			100000,
			1000000,
			10000000,
			100000000,
			1000000000,
			10000000000d,
			100000000000d,
			1000000000000d,
			10000000000000d,
			100000000000000d,
			//测试数据二
			110000000000000d,
			101000000000000d,
			100100000000000d,
			100010000000000d,
			100001000000000d,
			100000100000000d,
			100000010000000d,
			100000001000000d,
			100000000100000d,
			100000000010000d,
			100000000001000d,
			100000000000100d,
			100000000000010d,
			100000000000001d,
			//测试数据三
			101010101010101d,
			100100100100100d,
			100100010010001d,
			100100001000010d,
			100001000001000d,
			100010000100010d,
			111111111111111d,
			123456789012345d,
			//测试数据四(含小数)
			0.00,
			0.005,//0.01(转换成字符串后)
			0.015,//0.01
			0.025,//0.03
			0.035,//0.04
			0.045,//0.04
			0.055,//0.06
			1.384,
			10.125,
			100.02,
			1000.045,
			10000.055,
			100000.1,
			1000000.11,
			10000000.10,
			100000000.105,
			1000000000.010,
			//测试数据五(整数超过15位)
			1000000000000000d,
			1000000000000000.01d
		};
		
		for(double money : testData){
			String moneyStr = getDecimalStr(money);
			System.out.println( moneyStr + ":" + transform(moneyStr));
		}
	}
}

//打印结果:
/*
0:零圆整
1:壹圆整
10:壹拾圆整
100:壹佰圆整
1000:壹仟圆整
10000:壹万圆整
100000:壹拾万圆整
1000000:壹佰万圆整
10000000:壹仟万圆整
100000000:壹亿圆整
1000000000:壹拾亿圆整
10000000000:壹佰亿圆整
100000000000:壹仟亿圆整
1000000000000:壹万亿圆整
10000000000000:壹拾万亿圆整
100000000000000:壹佰万亿圆整
110000000000000:壹佰壹拾万亿圆整
101000000000000:壹佰零壹万亿圆整
100100000000000:壹佰万壹仟亿圆整
100010000000000:壹佰万零壹佰亿圆整
100001000000000:壹佰万零壹拾亿圆整
100000100000000:壹佰万零壹亿圆整
100000010000000:壹佰万亿壹仟万圆整
100000001000000:壹佰万亿零壹佰万圆整
100000000100000:壹佰万亿零壹拾万圆整
100000000010000:壹佰万亿零壹万圆整
100000000001000:壹佰万亿壹仟圆整
100000000000100:壹佰万亿零壹佰圆整
100000000000010:壹佰万亿零壹拾圆整
100000000000001:壹佰万亿零壹圆整
101010101010101:壹佰零壹万零壹佰零壹亿零壹佰零壹万零壹佰零壹圆整
100100100100100:壹佰万壹仟零壹亿零壹拾万零壹佰圆整
100100010010001:壹佰万壹仟亿壹仟零壹万零壹圆整
100100001000010:壹佰万壹仟亿零壹佰万零壹拾圆整
100001000001000:壹佰万零壹拾亿壹仟圆整
100010000100010:壹佰万零壹佰亿零壹拾万零壹拾圆整
111111111111111:壹佰壹拾壹万壹仟壹佰壹拾壹亿壹仟壹佰壹拾壹万壹仟壹佰壹拾壹圆整
123456789012345:壹佰贰拾叁万肆仟伍佰陆拾柒亿捌仟玖佰零壹万贰仟叁佰肆拾伍圆整
0:零圆整
0.01:零圆零壹分
0.01:零圆零壹分
0.03:零圆零叁分
0.04:零圆零肆分
0.04:零圆零肆分
0.06:零圆零陆分
1.38:壹圆叁角捌分
10.13:壹拾圆壹角叁分
100.02:壹佰圆零贰分
1000.04:壹仟圆零肆分
10000.06:壹万圆零陆分
100000.10:壹拾万圆壹角
1000000.11:壹佰万圆壹角壹分
10000000.10:壹仟万圆壹角
100000000.11:壹亿圆壹角壹分
1000000000.01:壹拾亿圆零壹分
1000000000000000:金额太大,不能处理整数部分超过15位的金额!
1000000000000000:金额太大,不能处理整数部分超过15位的金额!
*/ 

 

   个人觉得代码宜读、宜于维护才是最重要,转换大写这个小功能没有必要追求什么超高性能。

 

 

文章评论

那些争议最大的编程观点
那些争议最大的编程观点
程序员周末都喜欢做什么?
程序员周末都喜欢做什么?
“肮脏的”IT工作排行榜
“肮脏的”IT工作排行榜
我是如何打败拖延症的
我是如何打败拖延症的
总结2014中国互联网十大段子
总结2014中国互联网十大段子
不懂技术不要对懂技术的人说这很容易实现
不懂技术不要对懂技术的人说这很容易实现
漫画:程序员的工作
漫画:程序员的工作
鲜为人知的编程真相
鲜为人知的编程真相
我的丈夫是个程序员
我的丈夫是个程序员
“懒”出效率是程序员的美德
“懒”出效率是程序员的美德
程序员眼里IE浏览器是什么样的
程序员眼里IE浏览器是什么样的
要嫁就嫁程序猿—钱多话少死的早
要嫁就嫁程序猿—钱多话少死的早
老程序员的下场
老程序员的下场
10个帮程序员减压放松的网站
10个帮程序员减压放松的网站
当下全球最炙手可热的八位少年创业者
当下全球最炙手可热的八位少年创业者
Java程序员必看电影
Java程序员必看电影
我跳槽是因为他们的显示器更大
我跳槽是因为他们的显示器更大
程序员都该阅读的书
程序员都该阅读的书
程序员和编码员之间的区别
程序员和编码员之间的区别
5款最佳正则表达式编辑调试器
5款最佳正则表达式编辑调试器
一个程序员的时间管理
一个程序员的时间管理
旅行,写作,编程
旅行,写作,编程
Web开发者需具备的8个好习惯
Web开发者需具备的8个好习惯
编程语言是女人
编程语言是女人
十大编程算法助程序员走上高手之路
十大编程算法助程序员走上高手之路
中美印日四国程序员比较
中美印日四国程序员比较
程序员应该关注的一些事儿
程序员应该关注的一些事儿
老美怎么看待阿里赴美上市
老美怎么看待阿里赴美上市
 程序员的样子
程序员的样子
如何成为一名黑客
如何成为一名黑客
程序员的一天:一寸光阴一寸金
程序员的一天:一寸光阴一寸金
做程序猿的老婆应该注意的一些事情
做程序猿的老婆应该注意的一些事情
科技史上最臭名昭著的13大罪犯
科技史上最臭名昭著的13大罪犯
Java 与 .NET 的平台发展之争
Java 与 .NET 的平台发展之争
亲爱的项目经理,我恨你
亲爱的项目经理,我恨你
程序猿的崛起——Growth Hacker
程序猿的崛起——Growth Hacker
每天工作4小时的程序员
每天工作4小时的程序员
为什么程序员都是夜猫子
为什么程序员都是夜猫子
60个开发者不容错过的免费资源库
60个开发者不容错过的免费资源库
初级 vs 高级开发者 哪个性价比更高?
初级 vs 高级开发者 哪个性价比更高?
看13位CEO、创始人和高管如何提高工作效率
看13位CEO、创始人和高管如何提高工作效率
为啥Android手机总会越用越慢?
为啥Android手机总会越用越慢?
程序员必看的十大电影
程序员必看的十大电影
程序员最害怕的5件事 你中招了吗?
程序员最害怕的5件事 你中招了吗?
聊聊HTTPS和SSL/TLS协议
聊聊HTTPS和SSL/TLS协议
软件开发程序错误异常ExceptionCopyright © 2009-2015 MyException 版权所有