1. 程式人生 > >[簡易]中英文混合排序

[簡易]中英文混合排序

程式碼,(說明略,看註釋)

package utils;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 
 * 【簡易】中英文混合列表,首字母排序<br> 
 * 〈支援GBK中文編碼範圍 45217 - 55289 (十進位制)〉
 */
public class StringSortUtils {

    public
static void main(String[] args) { StringSortUtils sort = new StringSortUtils(); List<String> list = new ArrayList<String>(); list.add("adisen-A"); list.add("bulsi-B"); list.add("Kobe-K"); list.add("布丁-B"); list.add("杜甫-D"
); list.add("寶馬-B"); list.add("奔詞-B"); list.add("比爾-B"); list.add("嚓的撒-C");// 多音字,不在該範圍內 list.add("換手機-H"); list.add("天明-T"); list.add("吧馬-B"); list.add("元方-Y"); list.add("芭吧-B"); list.add("分割-F"); list.add("割列-G"
); list.add("啊-A"); list.add("#-0"); list.add("京東-J"); list.add("亞馬遜-Y"); list.add("撒旦-S"); List<String> newList = sort.sort(list); for (String string : newList) { System.out.println(string); } System.out.println("-----------------------分割線-----------------------"); Map<String, List<String>> map = sort.sortAsMap(newList, TYPE_UPPERCASE); String[] uppercaseTable = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "0" }; for (String string : uppercaseTable) { System.out.println(string + " : " + map.get(string)); } // 例舉:不在範圍內的中文字元 System.out.println(sort.getGBValue('嚓')); System.out.println(sort.getAlpha('嚓', 0)); System.out.println(sort.getGBValue('僮')); System.out.println(sort.getAlpha('僮', 0)); System.out.println(sort.getGBValue('咗')); System.out.println(sort.getAlpha('咗', 0)); } public static final int TYPE_UPPERCASE = 0; public static final int TYPE_LOWERCASE = 1; // 預設匹配字串陣列 // 大寫字串陣列 // 未匹配任何字母的,匹配0,排在最後 private String[] uppercaseTable = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "0" }; // 小寫字串陣列 // 未匹配任何字母的,匹配0,排在最後 private String[] lowercaseTable = { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0" }; /* * 1. 字母Z使用了兩個標籤,這裡有27個值 * 2. i, u, v都不做聲母, 跟隨前面的字母 * 3. 中文定義根據GBK編碼規律,選取對應26個字母發音的第一個中文,第27個為Z字母的最後一箇中文, * 例: 阿-45218,在 A-啊-45217和B-芭-45253內 * * 注意:還有很多字不在按照此規律,不在改範圍內,例如:多音字-嚓 ca cha -57578 * * 對應GBK的值: * 啊 : 45217 芭 : 45253 擦 : 45761 搭 : 46318 蛾 : 46826 發 : 47010 噶 : 47297 哈 : 47614 哈 : 47614 * 擊 : 48119 喀 : 49062 垃 : 49324 媽 : 49896 拿 : 50371 哦 : 50614 啪 : 50622 期 : 50906 然 : 51387 * 撒 : 51446 塌 : 52218 塌 : 52218 塌 : 52218 挖 : 52698 昔 : 52980 壓 : 53689 匝 : 54481 座 : 55289 * } */ private char[] chartable = { '啊', '芭', '擦', '搭', '蛾', '發', '噶', '哈', '哈', '擊', '喀', '垃', '媽', '拿', '哦', '啪', '期', '然', '撒', '塌', '塌', '塌', '挖', '昔', '壓', '匝', '座' }; /* 初始化陣列 * 明白了原理,可以去除 chartable 和程式碼塊,簡化為 : * private int[] table = { * 45217,45253,45761,46318,46826,47010,47297,47614,47614, * 48119,49062,49324,49896,50371,50614,50622,50906,51387, * 51446,52218,52218,52218,52698,52980,53689,54481,55289 * }; */ private int[] table = new int[27]; { // 普通程式碼塊 for (int i = 0; i < 27; ++i) { table[i] = getGBValue(chartable[i]); } } public StringSortUtils() { } /** * 獲取GBK(或gb2312)的漢字編碼 <br> * 〈gbk中文佔兩個位元組,英文佔一個位元組,當得到一個位元組時,返回0〉 * <pre> * getGBValue("吧") = 45257 * </pre> */ private int getGBValue(char ch){ String str = ch + ""; try{ byte[] bytes = str.getBytes("GBK"); if(bytes.length < 2) return 0; // 0xff00 = 65280, 0xff = 255 return (bytes[0] << 8 & 0xff00) + (bytes[1] & 0xff); }catch(UnsupportedEncodingException e) { return 0; } } /** * 中英文混合列表排序 <br> * 〈對中英文混合列表按照首字母排序〉 */ public List<String> sort(List<String> list) { List<String> result = new ArrayList<String>(); for(String str : uppercaseTable) { for (int i = 0; i < list.size(); i++) { if(str.equals(getAlpha(list.get(i).toString().charAt(0), TYPE_UPPERCASE))) { result.add(list.get(i).toString()); list.remove(i); i--; } } } return result; } /** * 排序,返回Map<br> * 〈字串列表,按照首字元的首字母進行排序,返回按照英文字母歸類的Map,Map的value值是對應英文字母下的字串列表〉 * * @param list * @param type 型別 -- 大/小寫(TYPE_UPCASE / TYPE_LOWERCASE)(0/1) * @return Map<String, List<String>> */ public Map<String, List<String>> sortAsMap(List<String> list, int type){ Map<String, List<String>> resultMap = new HashMap<String, List<String>>(); List<String> arr = new ArrayList<String>(); String [] table = (type == TYPE_UPPERCASE) ? uppercaseTable : lowercaseTable; for(String str : table) { for (int i = 0; i < list.size(); i++) { if(str.equals(getAlpha(list.get(i).toString().charAt(0), type))) { arr.add(list.get(i).toString()); list.remove(i); i--; } } resultMap.put(str, arr); arr = new ArrayList<String>(); } return resultMap; } /** * 得到字串的第一個字元的首字母<br> * <pre> * 英文字母返回對應的大小寫字母,中文按照大小對比,判斷該字的首字母. * 例: 啊(45217) < 阿(45218) < 芭(45253) * getAlpha('阿',TYPE_UPPERCASE) == A * </pre> */ public String getAlpha(char ch, int type) { // 英文字母返回對應的大小寫字母 if(ch >= 'a' && ch <= 'z') { return TYPE_UPPERCASE == type ? (char)(ch - 'a' + 'A') + "" : ch + ""; } if(ch >= 'A' && ch <= 'Z'){ return TYPE_UPPERCASE == type ? ch + "" : (char)(ch - 'A' + 'a') + ""; } // 如果該字元不在支援的中文字元編碼範圍內,又不為英文字母 int gb = getGBValue(ch); if(gb < table[0] || gb > table[26]) return "0"; // 遍歷得到字元首字母對應 table 陣列的位置 int i; for(i = 0; i < 26; ++i) { if(match(i, gb)) break; } if(i >= 26) { return "0"; } else { return TYPE_UPPERCASE == type ? uppercaseTable[i] + "" : lowercaseTable[i] + ""; } } private boolean match(int i, int gb) { if(gb < table[i]) return false; int j = i + 1; // 遇到不發聲的首字母 while(j < 26 && (table[j] == table[i])) ++j; // 字母Z使用了兩個標籤 return j == 26 ? gb <= table[j] : gb < table[j]; } }

輸出結果

adisen-A-A
bulsi-B
布丁-B
寶馬-B
奔詞-B
比爾-B
吧馬-B
芭吧-B
杜甫-D
分割-F
割列-G
換手機-H
京東-J
Kobe-K
撒旦-S
天明-T
元方-Y
亞馬遜-Y
嚓的撒-C
#-0
-----------------------分割線-----------------------
A : [adisen-A, 啊-A]
B : [bulsi-B, 布丁-B, 寶馬-B, 奔詞-B, 比爾-B, 吧馬-B, 芭吧-B]
C : []
D : [杜甫-D]
E : []
F : [分割-F]
G : [割列-G]
H : [換手機-H]
I : []
J : [京東-J]
K : [Kobe-K]
L : []
M : []
N : []
O : []
P : []
Q : []
R : []
S : [撒旦-S]
T : [天明-T]
U : []
V : []
W : []
X : []
Y : [元方-Y, 亞馬遜-Y]
Z : []
0 : [嚓的撒-C, #-0]
57578
0
55767
0
34296
0