题目分析
首先对读法做一下规范,我是做过两年审计工作,所以习惯于采用会计的大写方式
例如(没有测试所有格式,仅测试了如下个别代表性数据;这里的十均表示为"壹拾",间隔有零均读零):
数据 | 大写 | 数据 | 大写 | 数据 | 大写 |
---|---|---|---|---|---|
1 | 壹 | 10,100 | 壹萬零壹佰 | 110,110 | 壹拾壹萬零壹佰壹拾 |
10 | 壹拾 | 11,000 | 壹萬壹仟 | 111,001 | 壹拾壹萬壹仟零壹 |
100 | 壹佰 | 11,100 | 壹萬壹仟壹佰 | 1,000,000 | 壹佰萬 |
101 | 壹佰零壹 | 11,010 | 壹萬壹仟零壹拾 | 1,001,000 | 壹佰萬零壹仟 |
110 | 壹佰壹拾 | 10,110 | 壹萬零壹佰壹拾 | 1,100,101 | 壹佰壹拾萬零壹佰零壹 |
111 | 壹佰壹拾壹 | 111,011 | 壹拾壹萬壹仟零壹拾壹 | 1,100,101 | 壹佰壹拾萬零壹佰零壹 |
1,000 | 壹仟 | 110,111 | 壹拾壹萬零壹佰壹拾壹 | 1,101,100 | 壹佰壹拾萬零壹仟壹佰 |
1,001 | 壹仟零壹 | 101,111 | 壹拾萬零壹仟壹佰壹拾壹 | 1,110,100 | 壹佰壹拾壹萬零壹佰 |
1,010 | 壹仟零壹拾 | 100,010 | 壹拾萬零壹拾 | 1,111,000 | 壹佰壹拾壹萬壹仟 |
1,100 | 壹仟壹佰 | 100,100 | 壹拾萬零壹佰 | 10,010,000 | 壹仟零壹萬 |
1,011 | 壹仟零壹拾壹 | 101,000 | 壹拾萬零壹仟 | 10,100,001 | 壹仟零壹拾萬零壹 |
1,110 | 壹仟壹佰壹拾 | 110,000 | 壹拾壹萬 | 11,000,000 | 壹仟壹佰萬 |
1,101 | 壹仟壹佰零壹 | 100,011 | 壹拾萬零壹拾壹 | 10,010,001 | 壹仟零壹萬零壹 |
1,111 | 壹仟壹佰壹拾壹 | 100,101 | 壹拾萬零壹佰零壹 | 10,011,001 | 壹仟零壹萬壹仟零壹 |
10,100 | 壹萬零壹佰 | 101,001 | 壹拾萬壹仟零壹 | 10,010,100 | 壹仟零壹萬零壹佰 |
思路分析
本来想采用列举的方式一个一个写出来,就像下面这样:
public static void main(String[] args) {
int count = 0;
int plus;
//此处计算的是1-10,因为这些数字每个都是一个汉字;
for (int i = 1; i <= 10; i++) {
count += 1;
}
//此处计算的是11-20,因为这些数字每个都是两个汉字;
for (int i = 11; i <= 20; i++) {
count += 3;
}
//此处计算的是21-99,因为这些数字只要能被十整除,均是两个汉字(例如:二十,三十);只要不能被十整除,均是三个汉字(例如:二十三,四十七,九十九);
//这是还比较简单,不需要调用找零的个数方法;
for (int i = 21; i <= 99; i++) {
plus = i % 10 == 0 ? 2 : 3;
count += plus;
}
//此处计算的是100-999,此项比较麻烦,总体分为三种:
// 两个汉字(例如:三百,四百),他们的特点是整百整千,能够被100整除;
// 四个汉字(例如:二百零七,三百一十),他们的特点是含零,且只有一个零,种类较多,可以先看五个汉字的,然后剩下的都是四个汉字;
// 五个汉字(一百二十三,九百九十九),他们的特点是不含零;
for (int i = 100; i <= 999; i++) {
if (i % 100 == 0) {
plus = 2;
} else if (findZero(i) == 0) {
plus = 5;
} else {
plus = 4;
}
count += plus;
}
//此处计算的是1000-9999,从此处就开始往下麻烦,总体分为五种:
// 两个汉字(例如:两千,五千),他们的特点是整千整万,能够被1000整除;
// 四个汉字(例如:三千零一,一千一百,三千二百),他们的特点是去掉个位,可以被10整除,并且自己不能被十整除(例如:一千一百零一虽然满足去个位可被十整除,但是它有五位);
// 五个汉字(例如:一千零一十),他们的特点是,在前两者判断完成的前提下,自己能够被10整除,并且去掉两位也可以被10整除;
// 六个汉字(例如:一千七百三十,九千一百零一,一千零五十二),种类较多,可以先看七个汉字的,然后剩下的都是六个汉字;
// 七个汉字(例如:一千三百五十七),他的特点是,不含零,可以调用findZero的方法来进行计数;
for (int i = 1000; i <= 9999; i++) {
//此处括号里的(i % 1000 == 0)判定条件也可以替换为(findZero(i) == 3)
if (i % 1000 == 0) {
plus = 2;
} else if ((i % 10 != 0) && i / 10 % 10 == 0) {
plus = 4;
} else if ((i % 10 == 0) && i / 100 % 10 == 0) {
plus = 5;
} else if (findZero(i) == 0) {
plus = 7;
} else {
plus = 6;
}
count += plus;
}
System.out.println(count);
}
就像上面一样,直接卡在了一万以下,况且无法对随意数据进行取值,所以采用了另一种方法:即先进行大写转换,然后利用统计转换后的大写读法字符的长度来进行统计.
方法改进
具体思路
首先,最重要的是创建一种方法来把读法完成,即两种:一种是阿拉伯直接转换的数字(7→柒,0→零),另一种是位数(个十百千万,其中个不用读),所以先创建两个数组(下图为改进过的,万比较特殊,万前和万后读法相近,可以调用方法,所以把万字单独列出来)
char[] num = {'零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'};
char[] digit = {'拾', '佰', '仟'};
char[] digitHuge = {'萬'};
先创建方法来对两种读法进行分割:
下面代码的方法是对数字进行转化:
private static String getBigNumber(int numberR) {
int number = numberR;
char[] num = {'零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'};
String sNumber = String.valueOf(number);
char[] arr = sNumber.toCharArray();
char[] arr2 = new char[arr.length];
for (int i = 0; i < arr.length; i++) {
arr2[i] = num[Integer.parseInt(String.valueOf(arr[i]))];
}
StringBuffer str = new StringBuffer();
for (char s : arr2) {
str.append(s);
}
String numberBig = str.toString();
return numberBig;
}
下面代码的方法是对"位"进行转化:
private static String getDigit(int numberR) {
int number = numberR;
char[] digit = {'拾', '佰', '仟'};
String sNumber = String.valueOf(number);
char[] arr = sNumber.toCharArray();
char[] arr2 = new char[arr.length - 1];
for (int i = 0; i < arr.length - 1; i++) {
arr2[i] = digit[i];
}
StringBuffer str = new StringBuffer();
for (char s : arr2) {
str.append(s);
}
String digitDo = str.toString();
return digitDo;
}
然后就采用穿法取元素的方法进行拼接(比如三千五百零拾六–之后会对读法进行优化,现在先进行简单的拼接):
private static String nameChinese(int n) {
String bigNumber = getBigNumber(n);
char[] nnn = bigNumber.toCharArray();
String digit = getDigit(n);
char[] ddd = digit.toCharArray();
String sA = String.valueOf(n);
char[] arrA = sA.toCharArray();
char[] arr2 = new char[arrA.length * 2 - 1];
for (int i = 0; i < arrA.length * 2 - 1; i++) {
if (i % 2 == 0) {
arr2[i] = nnn[i / 2];
} else {
arr2[i] = ddd[ddd.length - i / 2 - 1];
}
}
StringBuffer str = new StringBuffer();
for (char s : arr2) {
str.append(s);
}
String s = str.toString().replace("零佰零拾", "零").replace("零佰", "零").replace("零拾", "零");
String noTailNumber;
if (n == 0) {
noTailNumber = "";
} else if (n % 100 == 0 && n >= 100) {
noTailNumber = s.substring(0, s.length() - 2);
} else if (n % 10 == 0 && n % 100 != 0 && n >= 10) {
noTailNumber = s.substring(0, s.length() - 1);
} else {
noTailNumber = s;
}
return noTailNumber;
}
这段代码中的
.replace(“零佰零拾”, “零”).replace(“零佰”, “零”).replace(“零拾”, “零”)
这一部分,本来是在此方法之后的取零步骤进行操作的,可是遇到了一些问题(末尾有零,其他位数后转换效果不好等情况),结果现在去不掉了,所以依旧留着.
拼接完成之后就是拼接"万"类的前后字符串:
private static String nameWanChinese(int n) {
String sN = String.valueOf(n);
char[] arrN = sN.toCharArray();
char[] arrStart = new char[arrN.length - 4];
char[] arrEnd = new char[4];
System.arraycopy(arrN, 0, arrStart, 0, arrN.length - 4);
System.arraycopy(arrN, arrN.length - 4, arrEnd, 0, 4);
StringBuffer strStart = new StringBuffer();
for (char s : arrStart) {
strStart.append(s);
}
String start = strStart.toString();
StringBuffer strEnd = new StringBuffer();
for (char s : arrEnd) {
strEnd.append(s);
}
String end = strEnd.toString();
if ((Integer.parseInt(end) < 1000 && Integer.parseInt(end) > 0) || (Integer.parseInt(start) % 10 == 0 && Integer.parseInt(start) >= 10&&Integer.parseInt(end)!=0)|| (Integer.parseInt(start) % 100 == 0 && Integer.parseInt(start) >= 100&&Integer.parseInt(end)!=0)|| (Integer.parseInt(start) % 1000 == 0 && Integer.parseInt(start) >= 1000&&Integer.parseInt(end)!=0)) {
return (nameChinese(Integer.parseInt(start)) + "萬零" + nameChinese(Integer.parseInt(end)));
} else {
return (nameChinese(Integer.parseInt(start)) + "萬" + nameChinese(Integer.parseInt(end)));
}
}
这里面最长的那一串是if ((Integer.parseInt(end) < 1000 && Integer.parseInt(end) > 0) || (Integer.parseInt(start) % 10 == 0 && Integer.parseInt(start) >= 10&&Integer.parseInt(end)!=0)|| (Integer.parseInt(start) % 100 == 0 && Integer.parseInt(start) >= 100&&Integer.parseInt(end)!=0)|| (Integer.parseInt(start) % 1000 == 0 && Integer.parseInt(start) >= 1000&&Integer.parseInt(end)!=0)),这段代码是为了让100,000,101,000,这类的数字准确输出读法,否则会出现"十万零"或者"十万一千"这样的错误读法.
接着,再创建方法来对不同的数据进行不同的方法调用:
private static String getZeroName(String s) {
String numberFinal;
if (Integer.parseInt(s) <= 9999 && Integer.parseInt(s) >= 0) {
numberFinal = nameChinese(Integer.parseInt(s));
} else if (Integer.parseInt(s) <= 99999999 && Integer.parseInt(s) >= 10000) {
numberFinal = nameWanChinese(Integer.parseInt(s));
} else
/* if (Integer.parseInt(s) <= 2147483647 && Integer.parseInt(s) >= 100000000) {
numberFinal = nameYiChinese(Integer.parseInt(s));
} else */ {
numberFinal = "数据溢出";
}
return numberFinal;
}
注释掉的代码原本是为了输出亿元部分,但是经过多次尝试,未能创造出合适的方法,不甘心,不舍得删除,所以依旧留着------------------------------
最后,对所得到的数据进行最后一次过滤:
private static String getFinalChineseName(String s) {
String zeroName = getZeroName(s);
String finalName = zeroName.replace("零萬", "萬").replace("零拾零萬", "萬").replace("零佰零拾", "零").replace("零佰", "零").replace("零拾", "零").replace("零萬", "萬").replace("零億", "億");
return finalName;
}
其实这步骤在思考过程中反而是最先想出来的,只不过这一步才进行了最彻底地实现.
最后就是主方法进行调用,并添加计数器进行统计
public static void main(String[] args) {
//char[] num = {'零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'};
//char[] digit = {'拾', '佰', '仟'};
//char[] digitHuge = {'萬', '億'};
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个数字");
String get = sc.next();
String OK = getFinalChineseName(get);
System.out.println(OK);//为了输出读法,方便进行验证
int count = 0;
for (int i = 1; i <= Integer.parseInt(get); i++) {
count += getFinalChineseName(String.valueOf(i)).length();
}
System.out.println(count);
}
完整代码
public class ReadAnyNumber {
public static void main(String[] args) {
long start = System.currentTimeMillis();
//char[] num = {'零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'};
//char[] digit = {'拾', '佰', '仟'};
//char[] digitHuge = {'萬', '億'};
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个数字");
String get = sc.next();
String OK = getFinalChineseName(get);
System.out.println(OK);
int count = 0;
for (int i = 1; i <= Integer.parseInt(get); i++) {
count += getFinalChineseName(String.valueOf(i)).length();
}
long end = System.currentTimeMillis();
System.out.println(count);
System.out.println("从一读到一亿需要读" + (count + 2) + "个汉字,共耗时" + (end - start) + "毫秒");
}
private static String getFinalChineseName(String s) {
String zeroName = getZeroName(s);
String finalName = zeroName.replace("零萬", "萬").replace("零拾零萬", "萬").replace("零佰零拾", "零").replace("零佰", "零").replace("零拾", "零").replace("零萬", "萬").replace("零億", "億");
return finalName;
}
private static String getZeroName(String s) {
String numberFinal;
if (Integer.parseInt(s) <= 9999 && Integer.parseInt(s) >= 0) {
numberFinal = nameChinese(Integer.parseInt(s));
} else if (Integer.parseInt(s) <= 99999999 && Integer.parseInt(s) >= 10000) {
numberFinal = nameWanChinese(Integer.parseInt(s));
} else
/* if (Integer.parseInt(s) <= 2147483647 && Integer.parseInt(s) >= 100000000) {
numberFinal = nameYiChinese(Integer.parseInt(s));
} else */ {
numberFinal = "数据溢出";
}
return numberFinal;
}
private static String nameWanChinese(int n) {
String sN = String.valueOf(n);
char[] arrN = sN.toCharArray();
char[] arrStart = new char[arrN.length - 4];
char[] arrEnd = new char[4];
System.arraycopy(arrN, 0, arrStart, 0, arrN.length - 4);
System.arraycopy(arrN, arrN.length - 4, arrEnd, 0, 4);
StringBuffer strStart = new StringBuffer();
for (char s : arrStart) {
strStart.append(s);
}
String start = strStart.toString();
StringBuffer strEnd = new StringBuffer();
for (char s : arrEnd) {
strEnd.append(s);
}
String end = strEnd.toString();
if ((Integer.parseInt(end) < 1000 && Integer.parseInt(end) > 0) || (Integer.parseInt(start) % 10 == 0 && Integer.parseInt(start) >= 10&&Integer.parseInt(end)!=0)|| (Integer.parseInt(start) % 100 == 0 && Integer.parseInt(start) >= 100&&Integer.parseInt(end)!=0)|| (Integer.parseInt(start) % 1000 == 0 && Integer.parseInt(start) >= 1000&&Integer.parseInt(end)!=0)) {
return (nameChinese(Integer.parseInt(start)) + "萬零" + nameChinese(Integer.parseInt(end)));
} else {
return (nameChinese(Integer.parseInt(start)) + "萬" + nameChinese(Integer.parseInt(end)));
}
}
private static String nameChinese(int n) {
String bigNumber = getBigNumber(n);
char[] nnn = bigNumber.toCharArray();
String digit = getDigit(n);
char[] ddd = digit.toCharArray();
String sA = String.valueOf(n);
char[] arrA = sA.toCharArray();
char[] arr2 = new char[arrA.length * 2 - 1];
for (int i = 0; i < arrA.length * 2 - 1; i++) {
if (i % 2 == 0) {
//if(n%10 != 0)
arr2[i] = nnn[i / 2];
} else {
arr2[i] = ddd[ddd.length - i / 2 - 1];
}
}
StringBuffer str = new StringBuffer();
for (char s : arr2) {
str.append(s);
}
String s = str.toString().replace("零佰零拾", "零").replace("零佰", "零").replace("零拾", "零");
String noTailNumber;
if (n == 0) {
noTailNumber = "";
} else if (n % 100 == 0 && n >= 100) {
noTailNumber = s.substring(0, s.length() - 2);
} else if (n % 10 == 0 && n % 100 != 0 && n >= 10) {
noTailNumber = s.substring(0, s.length() - 1);
} else {
noTailNumber = s;
}
return noTailNumber;
}
private static String getBigNumber(int numberR) {
int number = numberR;
char[] num = {'零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'};
String sNumber = String.valueOf(number);
char[] arr = sNumber.toCharArray();
char[] arr2 = new char[arr.length];
for (int i = 0; i < arr.length; i++) {
arr2[i] = num[Integer.parseInt(String.valueOf(arr[i]))];
}
StringBuffer str = new StringBuffer();
for (char s : arr2) {
str.append(s);
}
String numberBig = str.toString();
return numberBig;
}
private static String getDigit(int numberR) {
int number = numberR;
char[] digit = {'拾', '佰', '仟'};
String sNumber = String.valueOf(number);
char[] arr = sNumber.toCharArray();
char[] arr2 = new char[arr.length - 1];
for (int i = 0; i < arr.length - 1; i++) {
arr2[i] = digit[i];
}
StringBuffer str = new StringBuffer();
for (char s : arr2) {
str.append(s);
}
String digitDo = str.toString();
return digitDo;
}
}
最后结果别忘记加2,因为还有个"一亿"没统计,哈哈
顺便加入时间,看看我的笨方法需要耗时多久…………
//输出结果
请输入一个数字
99999999
玖仟玖佰玖拾玖萬玖仟玖佰玖拾玖
1412990003
从一读到一亿需要读1412990003个汉字,共耗时222302毫秒
缺点
显而易见,太坑了,居然耗时这么久!!
而且此方法也没有对亿进行分析!!
请教
希望各位大神对我这个方法提提意见,或者有更好的方法,让我学习学习