您的位置:首页 > 其它

[简易]中英文混合排序

2016-03-29 14:39 375 查看
代码,(说明略,看注释)

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: