[簡易]中英文混合排序
阿新 • • 發佈:2019-02-08
程式碼,(說明略,看註釋)
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