- 浏览: 460394 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
ty1972873004:
sunwang810812 写道我运行了这个例子,怎么结果是这 ...
Java并发编程: 使用Semaphore限制资源并发访问的线程数 -
lgh1992314:
simpleDean 写道请问,Logger.setLevel ...
Java内置Logger详解 -
sunwang810812:
我运行了这个例子,怎么结果是这样的:2号车泊车6号车泊车5号车 ...
Java并发编程: 使用Semaphore限制资源并发访问的线程数 -
jp260715007:
nanjiwubing123 写道参考你的用法,用如下方式实现 ...
面试题--三个线程循环打印ABC10次的几种解决方法 -
cb_0312:
SurnameDictionary文章我没看完,现在懂了
中文排序
对于一个数组或者列表或者集合的元素进行排序是一个比较常用的需求。现有的Java类库也提供了API来实现这样的功能,比如Arrays.sort以及Collections.sort的方法。另外,我们也可以用Collator来实现中文的排序。
package demo; import java.text.Collator; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Locale; public class TestCollator { public static void main(String[] args) { List<String> list = new ArrayList<String>(); list.add("中"); list.add("文"); list.add("拼"); list.add("音"); list.add("鑫"); list.add("犇"); Collections.sort(list, Collator.getInstance(Locale.CHINA)); for(String ele: list) { System.out.println(ele); } } }
输出的结果是:
拼
文
音
中
鑫
犇
中文排序后的结果,并不完全正确。
这是因为Java使用的是Unicode编码,而常用的中文编码是GB2312,它包含了7000个字符集而且是按照拼音排序的,也是连续的。GB18030和GBK都是在此基础上扩展起来的,这样就会造成Unicode的不连续性,最终导致对有些中文字符排序不完全正确的结果。
为了能够更好地对中文进行排序,我们可以采用拼音或者笔画来对中文进行排序。本文采用了拼音来排序。将汉语转换成拼音的开源项目有PinYin4j,下载的地址如下:
http://sourceforge.net/projects/pinyin4j/files/pinyin4j-2.5.0/pinyin4j-2.5.0/pinyin4j-2.5.0.zip/download
编写汉字转换成拼音的工具类
package demo; import java.io.UnsupportedEncodingException; import net.sourceforge.pinyin4j.PinyinHelper; import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType; import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat; import net.sourceforge.pinyin4j.format.HanyuPinyinToneType; import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType; import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination; public final class PinYinUtils { private PinYinUtils() { } /** * 判断一个字符是否是中文字符 */ private static boolean isChineseCharacter(char c) { return String.valueOf(c).matches("[\\u4E00-\\u9FA5]+"); } /** * 将一个含有中文的字符串转换成拼音。 * Note: 这里只是将中文转换成拼音,其它的各种字符将保持原来的样子。 */ public static String populatePinYing(String aChineseValue) { if (null == aChineseValue) { return null; } StringBuilder sb = new StringBuilder(); char[] charArray = aChineseValue.toCharArray(); HanyuPinyinOutputFormat outputFormat = new HanyuPinyinOutputFormat(); outputFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE); outputFormat.setVCharType(HanyuPinyinVCharType.WITH_V); outputFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE); for (int i = 0; i < charArray.length; i++) { if (isChineseCharacter(charArray[i])) { try { sb.append(PinyinHelper.toHanyuPinyinStringArray( charArray[i], outputFormat)[0]); } catch (BadHanyuPinyinOutputFormatCombination e) { e.printStackTrace(); } } else { sb.append(charArray[i]); } } return sb.toString(); } /** * 将一个含有中文的字符串转换成拼音。 * Note: 这里只是将中文转换成拼音,其它的各种字符将保持原来的样子。 * * 在這裡多了一個參數needToCorrectSpelling,这个主要用于调整姓氏的发音。 * 如 '单', 这个字作为姓氏念 shan, 但同时也有dan的发音等。 * * 为了保证姓氏发音的正确性,将了这个参数和相关的简单逻辑 */ public static String populatePinYing(String aChineseValue, boolean needToCorrectSpelling) { if (null == aChineseValue) { return null; } StringBuilder sb = new StringBuilder(); char[] charArray = aChineseValue.toCharArray(); HanyuPinyinOutputFormat outputFormat = new HanyuPinyinOutputFormat(); outputFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE); outputFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE); outputFormat.setVCharType(HanyuPinyinVCharType.WITH_V); String surname = null; for (int i = 0; i < charArray.length; i++) { if (isChineseCharacter(charArray[i])) { try { if (needToCorrectSpelling && 0 == i) { surname = SurnameDictionary .populateCorrectSpelling(charArray[i]); if (null == surname) { sb.append(PinyinHelper.toHanyuPinyinStringArray( charArray[i], outputFormat)[0]); } else { sb.append(surname); } } else { sb.append(PinyinHelper.toHanyuPinyinStringArray( charArray[i], outputFormat)[0]); } } catch (BadHanyuPinyinOutputFormatCombination e) { e.printStackTrace(); } } else { sb.append(charArray[i]); } } return sb.toString(); } public static void main(String[] args) throws UnsupportedEncodingException { String x = "拼音4j%^**Cool12568 カ キ "; System.out.println(populatePinYing(x)); } }
本文的一个简单例子是对名字进行排序,所以下面创建两个类 User 和 NameComparator
package demo; import java.io.Serializable; public class User implements Serializable { private static final long serialVersionUID = -1221268239932915488L; private String name; private int age; /** * @param name * @param age */ public User(String name, int age) { this.name = name; this.age = age; } public User() { } /** * @return the name */ public String getName() { return name; } /** * @param name * the name to set */ public void setName(String name) { this.name = name; } /** * @return the age */ public int getAge() { return age; } /** * @param age * the age to set */ public void setAge(int age) { this.age = age; } }
package demo; import java.util.Comparator; public class NameComparator implements Comparator<User> { public int compare(User u1, User u2) { String name1 = u1.getName(); String name2 = u2.getName(); return PinYinUtils.populatePinYing(name1).compareTo( PinYinUtils.populatePinYing(name2)); } }
测试代码如下:
package demo; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class Test { public static void main(String[] args) { run(); } private static void run() { List<User> list = prepareTestUserList(); printListBeforeSorting(list); Collections.sort(list, new NameComparator()); printListAfteSorting(list); } private static void printListAfteSorting(List<User> list) { System.out.println("After sorting....."); printList(list); } private static void printListBeforeSorting(List<User> list) { System.out.println("Before sorting....."); printList(list); } private static void printList(List<User> list) { for (User user : list) { System.out.println(user.getName()); } } private static List<User> prepareTestUserList() { List<User> list = new ArrayList<User>(); User u = new User(); u.setName("张三"); u.setAge(21); list.add(u); u = new User(); u.setName("李四"); u.setAge(18); list.add(u); u = new User(); u.setName("王五"); u.setAge(25); list.add(u); u = new User(); u.setName("鑫鑫"); u.setAge(89); list.add(u); u = new User(); u.setName("范范"); u.setAge(89); list.add(u); u = new User(); u.setName("单一号"); u.setAge(89); list.add(u); u = new User(); u.setName("犇犇"); u.setAge(89); list.add(u); return list; } }
Before sorting.....
张三
李四
王五
鑫鑫
范范
单一号
犇犇
After sorting.....
犇犇
单一号
范范
李四
王五
鑫鑫
张三
从上述的排序结果,可以看出“单一号”并没有在一个准确的位置上。产生这种情况是因为中文存在多音字,而且姓氏中的发音会不一样。如“单”在姓氏中需要发“shan”,用PinYin4j能够返回多音字,因为不知道哪一个正确,我在代码中返回了第一个 “dan”。
为了能够保证姓氏发声的正确性,个人想到的有三种:1. 数据库中存储姓氏发音的表
2. 将姓氏的发音存储在一个key-value的properties文件中
3. 创建一个姓氏发音的字典类
本文简单采用第三种方式来实现:
package demo; public class SurnameDictionary { public static String populateCorrectSpelling(char surname) { //TODO: if ('单' == surname) { return "shan"; } return null; } }
比较器中加入参数,将SurnameDictionary运用上去。
package demo; import java.util.Comparator; public class NameComparator implements Comparator<User> { public int compare(User u1, User u2) { String name1 = u1.getName(); String name2 = u2.getName(); return PinYinUtils.populatePinYing(name1, true).compareTo( PinYinUtils.populatePinYing(name2, true)); } }
重新运行结果,我们将得到正确的名字排序结果:
Before sorting.....
张三
李四
王五
鑫鑫
范范
单一号
犇犇
After sorting.....
犇犇
范范
李四
单一号
王五
鑫鑫
张三
评论
4 楼
cb_0312
2016-06-22
SurnameDictionary文章我没看完,现在懂了
3 楼
cb_0312
2016-06-22
SurnameDictionary.populateCorrectSpelling(charArray[i])
这个类是什么?我怎么找不到相关信息?
这个类是什么?我怎么找不到相关信息?
2 楼
MouseLearnJava
2013-07-17
oaklet 写道
只能做到这一步了,再向下没法做了,毕竟有些怪字音不确定,非人力所能为,例如
常见的姓氏用字异读有:
重:Chóng 音崇;
区:ōu 音欧;
仇:Qiú 音求;
秘:Bì 音闭;
冼:Xiǎn 音显;
解:Xiè 音谢;
折:Shè 音舌;
单:Shàn 音善;
朴:Piáo 音瓢;
翟:Zhá 音宅;
查:Zhā 音渣;
万俟:Mò qí 音莫奇;
尉迟:Yù chí 音玉迟;等等。
还有一些姓氏用字,一字两音,同一个作为姓氏的汉字,由于有两个读音,就代表了两个不同的姓,而且不一源流。如:“乐”姓,北方读音与“月”字同,而南方读音则与“勒”字同音;“召”姓,汉族人读者作“少”,而傣族人则读作“赵”;原籍在中原一带的“罩”姓,读音作“谈”,而注籍两广或壮族的则读音与“秦”字同。这些同字不同音者,分别表示不同的姓,不能认为是同一姓氏在不同地区、不同族属的不同读法。
常见的姓氏用字异读有:
重:Chóng 音崇;
区:ōu 音欧;
仇:Qiú 音求;
秘:Bì 音闭;
冼:Xiǎn 音显;
解:Xiè 音谢;
折:Shè 音舌;
单:Shàn 音善;
朴:Piáo 音瓢;
翟:Zhá 音宅;
查:Zhā 音渣;
万俟:Mò qí 音莫奇;
尉迟:Yù chí 音玉迟;等等。
还有一些姓氏用字,一字两音,同一个作为姓氏的汉字,由于有两个读音,就代表了两个不同的姓,而且不一源流。如:“乐”姓,北方读音与“月”字同,而南方读音则与“勒”字同音;“召”姓,汉族人读者作“少”,而傣族人则读作“赵”;原籍在中原一带的“罩”姓,读音作“谈”,而注籍两广或壮族的则读音与“秦”字同。这些同字不同音者,分别表示不同的姓,不能认为是同一姓氏在不同地区、不同族属的不同读法。
非常感谢你的评论。 姓氏用字异读方面,个人觉得能够通过建立一个发音词典库等方式加以改进。像姓氏一字多读的情况,发什么音不确定性太大,不好做。
在中文排序(如名字)上,尽可能考虑到姓氏异读的情况,对姓氏一字多音的情况保持一颗宽容的心吧。
其他博友有好的建议或意见,也请一起分享吧
1 楼
oaklet
2013-07-16
只能做到这一步了,再向下没法做了,毕竟有些怪字音不确定,非人力所能为,例如
常见的姓氏用字异读有:
重:Chóng 音崇;
区:ōu 音欧;
仇:Qiú 音求;
秘:Bì 音闭;
冼:Xiǎn 音显;
解:Xiè 音谢;
折:Shè 音舌;
单:Shàn 音善;
朴:Piáo 音瓢;
翟:Zhá 音宅;
查:Zhā 音渣;
万俟:Mò qí 音莫奇;
尉迟:Yù chí 音玉迟;等等。
还有一些姓氏用字,一字两音,同一个作为姓氏的汉字,由于有两个读音,就代表了两个不同的姓,而且不一源流。如:“乐”姓,北方读音与“月”字同,而南方读音则与“勒”字同音;“召”姓,汉族人读者作“少”,而傣族人则读作“赵”;原籍在中原一带的“罩”姓,读音作“谈”,而注籍两广或壮族的则读音与“秦”字同。这些同字不同音者,分别表示不同的姓,不能认为是同一姓氏在不同地区、不同族属的不同读法。
常见的姓氏用字异读有:
重:Chóng 音崇;
区:ōu 音欧;
仇:Qiú 音求;
秘:Bì 音闭;
冼:Xiǎn 音显;
解:Xiè 音谢;
折:Shè 音舌;
单:Shàn 音善;
朴:Piáo 音瓢;
翟:Zhá 音宅;
查:Zhā 音渣;
万俟:Mò qí 音莫奇;
尉迟:Yù chí 音玉迟;等等。
还有一些姓氏用字,一字两音,同一个作为姓氏的汉字,由于有两个读音,就代表了两个不同的姓,而且不一源流。如:“乐”姓,北方读音与“月”字同,而南方读音则与“勒”字同音;“召”姓,汉族人读者作“少”,而傣族人则读作“赵”;原籍在中原一带的“罩”姓,读音作“谈”,而注籍两广或壮族的则读音与“秦”字同。这些同字不同音者,分别表示不同的姓,不能认为是同一姓氏在不同地区、不同族属的不同读法。
发表评论
-
工厂类中移除if/else语句
2016-07-10 19:52 853面向对象语言的一个强大的特性是多态,它可以用来在代码中移除 ... -
Java编程练手100题
2014-12-11 17:13 6672本文给出100道Java编程练手的程序。 列表如下: 面 ... -
数组复制的三种方法
2014-11-30 12:57 2179本文将给出三种实现数组复制的方法 (以复制整数数组为例)。 ... -
数组复制的三种方法
2014-11-30 12:54 0本文将给出三种实现数组复制的方法 (以复制整数数组为例)。 ... -
四种复制文件的方法
2014-11-29 13:21 1688尽管Java提供了一个类ava.io.File用于文件的操 ... -
判断一个字符串中的字符是否都只出现一次
2014-11-25 12:58 2661本篇博文将给大家带来几个判断一个字符串中的字符是否都只出现一 ... -
使用正则表达式判断一个数是否为素数
2014-11-23 13:35 2107正则表达式能够用于判断一个数是否为素数,这个以前完全没有想过 ... -
几个可以用英文单词表达的正则表达式
2014-11-21 13:12 3703本文,我们将来看一下几个可以用英文单词表达的正则表达式。这些 ... -
(广度优先搜索)打印所有可能的括号组合
2014-11-20 11:58 1920问题:给定一个正整n,作为括号的对数,输出所有括号可能 ... -
随机产生由特殊字符,大小写字母以及数字组成的字符串,且每种字符都至少出现一次
2014-11-19 14:48 3943题目:随机产生字符串,字符串中的字符只能由特殊字符 (! ... -
找出1到n缺失的一个数
2014-11-18 12:57 3119题目:Problem description: You h ... -
EnumSet的几个例子
2014-11-14 16:24 8709EnumSet 是一个与枚举类型一起使用的专用 Set 实现 ... -
给定两个有序数组和一个指定的sum值,从两个数组中各找一个数使得这两个数的和与指定的sum值相差最小
2014-11-12 11:24 3286题目:给定两个有序数组和一个指定的sum值,从两个数组 ... -
Java面试编程题练手
2014-11-04 22:49 6657面试编程 写一个程序,去除有序数组中的重复数字 编 ... -
Collections用法整理
2014-10-22 20:55 9799Collections (java.util.Collect ... -
The Code Sample 代码实例 个人博客开通
2014-09-04 18:48 1376个人博客小站开通 http://thecodesample. ... -
Collections.emptyXXX方法
2014-06-08 13:37 2105从JDK 1.5开始, Collections集合工具类中预先 ... -
这代码怎么就打印出"hello world"了呢?
2014-06-08 00:37 7356for (long l = 4946144450195624L ... -
最短时间过桥
2014-04-21 22:03 4073本文用代码实现最短时间过桥,并且打印如下两个例子的最小过桥时间 ... -
将数组分割成差值最小的子集
2014-04-20 22:34 2842本文使用位掩码实现一个功能 ==》将数组分割成差值最小的子集 ...
相关推荐
java实现中文排序,按数字字母汉字的顺序进行排序
一种非常简单的方式解决Sqlite中文排序问题(网页)
EasyUI Datagrid 中文排序的问题 解决了WEB端和后台(Oracle、MySQL)中文排序问题
数字,字母,中文排序实现,用正则表达式判断字符串的类型。
小程序案例视频,汉字排序
SQL用中文字段排序,默认是按拼音来排的。 MSSQL2005不是这样的,那么排序问题怎么解决呢? 很简单,加上我们希望根据什么来(拼音或者笔画)排序的排序规则就好了。
在线中英文根据首字母排序工具: http://tools.jb51.net/aideddesign/zh_paixu 您可能感兴趣的文章:mysql的中文数据按拼音排序的2个方法mysql如何按照中文排序解决方案MySQL按照汉字的拼音排序简单实例
Qt5自带QCollator和QLocale库,结合qSort()函数,在VS2015开发工具下实现排序,支持中文英文排序,其中中文按照首字母排序,也可以设置按找笔画排序
一个简单的demo,关于中英文排序,一个java Demo
整理的Java汉字排序................................只是学习
js option 中文排序
中文排序问题,轻松搞定,如有问题,欢迎追问。
js中文排序算法,不用自己比较unicode
Android中英文混合排序,中文的拼音与英文字符串比较后排序
实现ios通讯录的中文排序的关键代码段 参考http://my.oschina.net/u/868062/blog/205098
EXT支持GRID中文排序 主要是重写排序的方法
Extjs grid 中文排序问题修正,其实很简单,请自己看源代码
js实现中英文混合排序,支持所有浏览器,包括谷歌
Flex 汉字排序,不过这个只能判断大部分汉字,一些特殊的字符,搞不定,比如“旮旯”等特殊汉字
oracle__汉字排序