您的位置:首页 > 编程语言 > Java开发

Java实现浮点数转换成人民币读法字符串

2012-11-14 15:48 489 查看
在这里,首先声明一点:以下算法处理的数值整数部分最多为12位(也就是最多可以读到“几千亿”,如果需要扩展"万亿",只需在此基础上做小的更改即可,原理是一样的'),同时,输入数值默认大于0。

首先,自已实现这个函数的大方面的思路是:首先把这个浮点数分成整数部分和小数部分。提取整数部分很容易,直接将这个浮点数强制类型转换成一个整数即可,这个整数就是浮点数的整数部分;再使用浮点数减去整数就可以得到这个浮点数的小数部分。

接下来,分开处理整数部分和小数部分。小数部分的处理很简单,直接将小数截断到保留2位数字,转换成几角几分的字符串即可:
例如:小数部分为0.783,截断后(关于这里是否四舍五入的问题,则可以看具体要求了,一点点的差别罢了)为0.78,直接将“7”、“8”转换成人民币读法,然后分别在后面加上“角”和“分”即可。

重点和难点在于整数部分,这部分处理则稍微复杂一点:比如整数部分长度不一的问题;加单位“亿、万”的问题;中间一个零的问题;最后一个零的问题;中间连续多个零的问题;末尾多个零的问题等等。但静下心来分析不难发现:中国的数字习惯是4位一节的,一个4位的数字可被转成几千几百几十几(在这里还是一般情况,未考虑0的情况,不急,后面慢慢解决,考虑的是大的方向),至于后面添加什么单位则不确定,如果这节4位数字出现在1~4位(但且从最低位开始算起),则后面添加单位元;如果这节4位数字出现在5~8位,则后面添加单位万;如果这节4位数字出现在9~12位,则后面添加单位亿;多于12位这里暂不考虑。

这里,设想已经输入一个浮点数,并且已成功地取得了它的整数部分(由于把该浮点数强制转换成long类型值作为整数部分后,浮点数最高位的0是自动消除的,所以整数部分的处理不必考虑最高位存在若干0的问题)和小数部分,并且均赋给了long类型的变量(这里先不考虑整数部分等于0的情形,程序中单独处理)。

然后,把代表整数部分的long类型变量转换成String类型,取得该String的长度len,接下来就是遍历这个字符串了(一层for循环)。那么,对于正在处理的第i个字符,就存在很多问题值得思考了。下面列出在循环里可能遇到的情况和相应的解决方法:

Q1:要问自已的第一个问题是:这个字符是属于1~4位、或者5~8位呢,还是处于9~12位呢?在这里,假设1~4位是第0段,5~8位是第1段,9~12位是第2段。这里我是这样解决这个问题的,利用(len - i - 1) / 4来计算该字符属于哪一段(本人在下面已经测试过,不信的人可以自已在草稿上测试)。
Q2:确定了当前字符属于哪一段之后,那么,在该段内部,考虑到一个字符在段的不同位置需要不同处理的问题(比如:处于某段最后一位的话,就得考虑加‘亿’/‘万’/‘元’单位的问题;处于非最后一位的话,就得考虑加‘仟’/‘佰’/‘十’的问题;同样是0对于具体位置也可能要进行不同的处理),所以这里就得问自已:当前正在处理的第i个字符处于特定段的第几位?我们暂且认为一个段是四位充足的,并且定义从低位开始算起,依次的位置编码为:0、1、2、3.例如:某个段的四个数字为"1234",那么‘4’在该段的位置编码为:0;‘3’在该段的位置编码为:1;‘2’在该段的位置编码为:2;‘1’在该段的位置编码为:3.那么怎么计算这个所谓的位置呢?这里我利用(len
- i - 1) % 4来计算该位置。(大家可以在草稿上举例计算以验证其正确性)
Q3:对非0的数字该怎么处理呢?这种情况很简单,只需将对应的阿拉伯数字转换成繁体的汉字,然后再在后面跟上单位即可。但值得提醒的是:每段的最低位处理时,千万别忘了加对应的‘亿’/‘万’/‘元’的单位哦。
Q4:对于0这个“捣乱”的家伙该怎么处理呢?这种情况就比较复杂了。
1. 我们先讨论一个段里不包含连续两个以上0的情况:
1)如果某段的最低位为0,那么这个0是不需要翻译成‘零’的,直接在结果字符串上添加段的单位(亿、万、元)即可。例如:610 xxxx . xxx,我们读作“陆佰壹十万xxxxx”
2)如果某段的非最低位为0,那么这个0是要被翻译成‘零’的。例如:601xxxx.xxx,我们读作“陆佰零壹万xxxxx”
2. 现在,我们讨论一个段里包含连续两个以上0的情况:
1)一般情况,当我们遇到第一个0的时候,将它翻译成‘零’,当遇到连续的第2个0的时候,就直接continue了,也就是说每次遇到0时,都要对这个结果字符串的最后一个字符进行判断,如果该字符不为'零',则将当前字符翻译成‘零’,如果该字符为'零',则跳过进行下一次循环。例如:6001 xxxx.xxx,我们将两个0合并并读作“陆仟零壹万xxxxx”。(这里说的一般情况为:连续的两个0没有位于一个段的最后一位)
2)如果连续的两个以上的0占据了某段的最低两位,例如:600 xxxx.xxx,这个时候,就不能单纯地用上面的处理方法了,因为,如果按照上面的处理方法的话, 就被读作“陆佰零万xxxxx”了,显然是不正确的,所以,在这里,对于这个特殊的最低位,我们要拿出来单独处理:先判断当前字符是不是某段最后一位,如果是,再 判断当前字符是不是‘0’,如果是,则必须对结果字符串进行判断,如果结果字符串的最后一个字符为‘零’,则必须删除这个‘零’,然后加段单位,如果结果字符串的最后 一个字符不为‘零’,则直接在结果字符串末尾加段单位。
3)我们也不排除这样一种可能:连续两个以上的0作为跨段的存在,例如:600 0123.xxx,那么如果循环处理到第三个0的字符处,我们就不能根据整数字符串的当前字符的前一个字符是否为0来处理了,因为,如果那样的话,这个0是不被翻译的,那么就被读成“陆佰万壹百贰十叁xxxx”了,显然也是不对的,我们期望的是读成“陆佰万零壹百贰十叁xxx”的。可见,如果一个0处于某段的最开始的位置,那也是要单独处理的,也就是说,跟当前字符在该段的位置有关喽,分析到这里,解决办法就有了:无非是多个if判断嘛。也就是要考察结果字符串的最后一个字符是否为'零'了,即,跨段的连续多个0只能读出一个'零'且必须读出一个'零'。
4)解决了上面的问题之后,接下来就又有新的问题了:例如:600 0000 xxxx.xxx,我们是不能读成“陆佰亿零万xxxxx”的,这显然是不对的。所以我们还有工作要做,导致上面的错误,无非是因为连续的4个0的那段的最后一个0没有处理好,如果在处理这个0的时候,对结果字符串再做下相关的处理,问题就可以解决了。处理 过程为(当前扫描字符为段的最后一个字符,并且该字符为'0'):第一种情况:结果字符串的最后一个字符为‘零’,并且结果字符串的倒数第二个字符为‘亿’或者‘万’,这种情况说明什么呢?说明该数值的这个段是全为0的,那么,这个结果字符串的最后一个'零'字符要保留,直接continue即可。例如:600
0000 1234.xxx,应该读作“陆佰亿零壹仟贰佰叁十肆xxx”。 第二种情况:结果字符串的最后一个字符为‘零’,并且结果字符串的倒数第二个字符既不是‘亿’也不是‘万’,这种情况说明什么呢?说明该数值的这个段并非全为0,所以要进行的操作是:将结果字符串的最后那个'零'字符删除并加上段单位即可。例如:600 0100 1234.xxx,应该读作“陆佰亿零壹佰万壹千贰佰叁十肆xxx".

还有一个小问题就是:人民币读法的规范,期间也问过了几个同学,他们的看法也不一致。例如:60 0000 1234是读作“陆十亿零壹仟贰佰叁十肆”呢?还是读作“陆十亿壹仟贰佰叁十肆”呢?呵呵,算法在这里,是依据第一种读法来写的。如果有确定如何读的,麻烦大家也可以告知我。万分感谢!

讨论到这,差不多所有的情况都考虑到了,如果大家发现存在没有考虑到的情况,欢迎大家指出来一块完善。下面将对整数部分处理的算法列出如下:

int len = zhengStr.length();//取整数部分字符串长度
for(i = 0; i < len; i++)//遍历整个整数字符串
int temp = zhengStr.charAt(i) - 48;//当前字符转为数值
int part = (len - i - 1) / 4;//当前字符位于那一段
int location = (len - i - 1) % 4;//当前字符处于段的那一个位置
if 当前字符不是本段最后一个
if 当前字符不为‘0’ result += 转换成的繁体字 + 单位; continue;
else 当前字符为‘0’
if 当前字符是该段第一个字符并且result串的最后一个字符 != '零' result += '零'; continue;
else
if result串的最后一个字符为'零' continue;
else result串的最后一个字符不为'零' result += '零';
else 当前字符是本段最后一个
if 当前字符不为‘0’ result += 转换成的繁体字 + 段单位; continue;
else 当前字符为'0'
if result串的最后一个字符 != '零' result += 段单位; continue;
else resutl串的最后一个字符 == '零'
if result串的倒数第二个字符为'亿'或者‘万’ continue;
else result串的倒数第二个字符不为'亿'或者'万' result += result串去零 + 段单位; continue;

下面附上整个程序源代码:
public class NumToRmb {

private final String[] hanArr = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};
private final String[] unitArr = {"仟", "", "十", "佰"};
private final String[] tag = {"元", "万", "亿"};

public String toHanStr(double num) {

String result = "";

long zheng = (long)num;
//long xiao = Math.round((num - zheng) * 100);//如果需要四舍五入,就用这个方法,但是小数点后
//两位依次为99时,第三位不能>=5,否则会报错
long xiao = (long)((num - zheng) * 100);//如果不需要四舍五入,就用这个方法

/*整数部分为0单独考虑*/
if(0 == zheng) {

int tempJiao = (int)(xiao / 10);
int tempFen = (int)(xiao % 10);

if(tempJiao != 0) {
result += hanArr[tempJiao] + "角";
}
if(tempFen != 0) {
result += hanArr[tempFen] + "分";
}

return result;
}

String zhengStr = String.valueOf(zheng);
int len = zhengStr.length();

int tempLen = 0;

/*处理整数部分*/
for(int i = 0; i < len; i++) {

int temp = zhengStr.charAt(i) - 48;
int part = (len - i - 1) / 4; //当前字符处于哪个段
int location = (len - i - 1) % 4; //当前字符处于该段的具体哪个位置

if(location != 0) { //不是该段的最后一个

if(temp != 0) { //当前字符不为0
result += hanArr[temp] + unitArr[(len - i) % 4]; continue;
} else { //当前字符为0
tempLen = result.length();
if(3 == location && result.charAt(tempLen - 1) != '零') { //当前字符为0且为该段第一个
result += "零"; continue;
} else {
tempLen = result.length();
if(result.charAt(tempLen - 1) == '零') {
continue;
} else {
result += "零"; continue;
}
}
}
} else { //是该段最后一个
if(temp != 0) {
result += hanArr[temp] + tag[part]; continue;
} else {
tempLen = result.length();
if(result.charAt(tempLen - 1) != '零') {
result += tag[part]; continue;
} else {
if(result.charAt(tempLen - 2) == '亿' || result.charAt(tempLen - 2) == '万') {
continue;
} else {
result = result.substring(0, tempLen - 1) + tag[part]; continue;
}
}
}
}

}

/*处理小数部分*/
int jiao = (int)(xiao / 10);
int fen = (int)(xiao % 10);

if(jiao != 0) {
result += hanArr[jiao] + "角";
}
if(fen != 0) {
result += hanArr[fen] + "分";
}

/*排除输入形式如60 0000 0000.00,输出为“陆十亿零”的情况*/
tempLen = result.length();
if(result.charAt(tempLen - 1) == '零') {
result = result.substring(0, tempLen - 1);
}
tempLen = result.length();
if(result.charAt(tempLen - 1) == '元') {
result += "整";
}
if(result.charAt(tempLen - 1) == '万' || result.charAt(tempLen - 1) == '亿') {
result += "元整";
}

return result;
}
public static void main(String[] args) {

NumToRmb ntr = new NumToRmb();
System.out.println(ntr.toHanStr(6000000000.0000));
System.out.println(ntr.toHanStr(600100.000));
System.out.println(ntr.toHanStr(6000.000));
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: