數字工具類-數字轉漢字
阿新 • • 發佈:2018-11-24
數字轉漢字的原理:
拆分:由於整數部分要加權值,而小數部分直接轉換即可,所以首先要將數字拆分成整數+小數;
整數處理:按照我們的中國人的習慣,把數字格式化成4位一組,不足4位前面補0。每次處理4位,按位匹配陣列中的漢字+權值。即按照數值找數字陣列(num_lower 、num_upper )中對應位置的漢字,按照在4位中的偏移量在單位權值陣列(unit_lower 、unit_upper )中找。比如21,轉化4位為0021,前面的0不用管,2對應數字“二”,權值是“十”,1對應數字“一”,權值是“(個)”用空字串代替。即得到“二十一”。每4位處理完後,還要整體對應一個權值,比如“萬、億、兆”等;
小數處理:小數部分直接按位對應漢字陣列和權值即可。
廢話了這麼多,可能雲裡霧裡的,看看具體程式碼吧:
//num 表示數字,lower表示小寫,upper表示大寫 private static final String[] num_lower = { "零", "一", "二", "三", "四", "五", "六", "七", "八", "九" }; private static final String[] num_upper = { "零", "壹", "貳", "叄", "肆", "伍", "陸", "柒", "捌", "玖" }; //unit 表示單位權值,lower表示小寫,upper表示大寫 private static final String[] unit_lower = { "", "十", "百", "千" }; private static final String[] unit_upper = { "", "拾", "佰", "仟"}; private static final String[] unit_common = {"","萬", "億","兆","京","垓","秭","穰","溝","澗","正","載"}; //允許的格式 private static final List<String> promissTypes = Arrays.asList("INTEGER","INT","LONG","DECIMAL","FLOAT","DOUBLE","STRING","BYTE","TYPE","SHORT"); /** * 數字轉化為小寫的漢字 * * @param num 將要轉化的數字 * @return */ public static String toChineseLower(Object num){ return format(num, num_lower, unit_lower); } /** * 數字轉化為大寫的漢字 * * @param num 將要轉化的數字 * @return */ public static String toChineseUpper(Object num){ return format(num, num_upper, unit_upper); } /** * 格式化數字 * * @param num 原數字 * @param numArray 數字大小寫陣列 * @param unit 單位權值 * @return */ private static String format(Object num,String[] numArray,String[] unit){ if(!promissTypes.contains(num.getClass().getSimpleName().toUpperCase())){ throw new RuntimeException("不支援的格式型別"); } //獲取整數部分 String intnum = getInt(String.valueOf(num)); //獲取小數部分 String decimal = getFraction(String.valueOf(num)); //格式化整數部分 String result = formatIntPart(intnum,numArray,unit); if(!"".equals(decimal)){//小數部分不為空 //格式化小數 result += "點"+formatFractionalPart(decimal, numArray); } return result; } /** * 格式化整數部分 * * @param num 整數部分 * @param numArray 數字大小寫陣列 * @return */ private static String formatIntPart(String num,String[] numArray,String[] unit){ //按4位分割成不同的組(不足四位的前面補0) Integer[] intnums = split2IntArray(num); boolean zero = false; StringBuffer sb = new StringBuffer(); for(int i=0;i<intnums.length;i++){ //格式化當前4位 String r = formatInt(intnums[i], numArray,unit); if("".equals(r)){// if((i+1)==intnums.length){ sb.append(numArray[0]);//結果中追加“零” }else{ zero=true; } }else{//當前4位格式化結果不為空(即不為0) if(zero || (i>0 && intnums[i]<1000)){//如果前4位為0,當前4位不為0 sb.append(numArray[0]);//結果中追加“零” } sb.append(r); sb.append(unit_common[intnums.length-1-i]);//在結果中新增權值 zero=false; } } return sb.toString(); } /** * 格式化小數部分 * * @param decimal 小數部分 * @param numArray 數字大小寫陣列 * @return */ private static String formatFractionalPart(String decimal,String[] numArray) { char[] val = String.valueOf(decimal).toCharArray(); int len = val.length; StringBuilder sb = new StringBuilder(); for (int i = 0; i < len; i++) { int n = Integer.valueOf(val[i] + ""); sb.append(numArray[n]); } return sb.toString(); }
拆分整數和小數的方法在這裡:
/** * 獲取整數部分 * * @param num * @return */ private static String getInt(String num){ //檢查格式 checkNum(num); char[] val = String.valueOf(num).toCharArray(); StringBuffer sb = new StringBuffer(); int t , s = 0; for (int i = 0; i < val.length; i++) { if(val[i]=='.') { break; } t = Integer.parseInt(val[i]+"",16); if(s+t==0){ continue; } sb.append(t); s+=t; } return (sb.length()==0? "0":sb.toString()); } /** * 獲取小數部分 * * @param num * @return */ private static String getFraction(String num){ int i = num.lastIndexOf("."); if(num.indexOf(".") != i){ throw new RuntimeException("數字格式不正確,最多隻能有一位小數點!"); } String fraction =""; if(i>=0){ fraction = getInt(new StringBuffer(num).reverse().toString()); if(fraction.equals("0")){ return ""; } } return new StringBuffer(fraction).reverse().toString(); } /** * 檢查數字格式 * * @param num */ private static void checkNum(String num) { if(num.indexOf(".") != num.lastIndexOf(".")){ throw new RuntimeException("數字["+num+"]格式不正確!"); } if(num.indexOf("-") != num.lastIndexOf("-") || num.lastIndexOf("-")>0){ throw new RuntimeException("數字["+num+"]格式不正確!"); } if(num.indexOf("+") != num.lastIndexOf("+")){ throw new RuntimeException("數字["+num+"]格式不正確!"); } if(num.indexOf("+") != num.lastIndexOf("+")){ throw new RuntimeException("數字["+num+"]格式不正確!"); } if(num.replaceAll("[\\d|\\.|\\-|\\+]", "").length()>0){ throw new RuntimeException("數字["+num+"]格式不正確!"); } }
通過這種分而治之的思路,處理起來就簡單多了。寫個main函式呼叫一下:
public static void main(String[] args) {
short s = 10;
byte b=10;
char c='A';
Object[] nums = {s, b, c, 0, 1001, 100100001L, 21., 205.23F, 205.23D, "01000010", "1000000100105.0123", ".142", "20.00", "1..2", true};
System.out.println("將任意數字轉化為漢字(包括整數、小數以及各種型別的數字)");
System.out.println("--------------------------------------------");
for(Object num :nums){
try{
System.out.print("["+num.getClass().getSimpleName()+"]"+num);
for(int i=0;i<25-String.valueOf(num+num.getClass().getSimpleName()).length();i+=4){
System.out.print("\t");
}
//呼叫轉化為小寫和大寫
System.out.print(" format:"+toChineseLower(num));
System.out.println("【"+toChineseUpper(num)+"】");
}catch(Exception e){
System.out.println(" 錯誤資訊:"+e.getMessage());
}
}
}
看看結果吧:
從上述程式碼和執行結果中,我們可以看到該功能支援多種資料型別的轉換、支援轉化為一般漢字和財務專用大寫漢字。還可以智慧處理非正常邏輯的數字。比如“20”會轉化為“二十”而非“二十零”;“1 0000 0001” 轉換成“一億零一”而非“一億零萬零一”。