- 浏览: 172193 次
- 性别:
- 来自: 湖南/株洲
文章分类
最新评论
-
53873039oycg:
强悍,学习!!!
java使用Unicode码对中文进行排序 -
zhige1202:
MyEclipse那个下不了啊,,进不了MyEclipse的官 ...
eclipse 插件大全 -
imcaptor:
如果tomcat/lib和WEB-INF/lib下面同时有st ...
Unable to load bean: type: struts-derfault.xml异常 -
yzmduncan:
犀利
java使用Unicode码对中文进行排序 -
空谷悠悠:
LZ的第二步说明采用link方式,但实际上仍然是直接拷贝的fe ...
Myeclipse6或6.5反编译工具安装
在Java中,对一个数组或列表(在本文中统称为集合)中的元素排序,是一个很经常的事情。好在Sun公司在Java库中实现了大部分功能。如果集合中的元素实现了Comparable接口,调用以下的静态(static)方法,就可以直接对集合排序。
// 数组排序方法
// 数组中的元素可以是像int这样的原生类型(primitive type), 也可以是像String这样实现了Comparable接口的类型,这里用type表示。
java.util.Arrays.sort(type[] a);
// 列表
public static <T> void sort(List<T> list)
以上的这些排序方式能满足大部分应用。但集合中的元素没有实现Comparable接口,或者集合中的元素要按一种特别的方式排序,这要怎么办?Sun公司早就想到了,并在Java库中提供上面两个方法的重载。
// 数组排序方法。
// 数组中的元素可以是像int这样的原生类型(primitive type), 也可以是像String这样实现了Comparable接口的类型,这里用type表示。
public static <T> void sort(T[] a, Comparator<? super T> c)
// 列表
public static <T> void sort(List<T> list, Comparator<? super T> c)
只要实现了Comparator接口,就可以按程序员自己的意思去排序了。对于包含汉字的字符串来说,排序的方式主要有两种:一种是拼音,一种是笔画。汉字是通过一定的编码方式存储在计算机上的,主要的编码有:Unicdoe、GB2312和GBK等。
Unicode 编码中的汉字
Unicode中编码表分为两块,一个是基本的,一个是辅助的。现在的大多数操作系统还不支持Unicode中辅助区域中的文字,如WinXp。
在Java中的字符就是Unicode码表示的。对于Unicode基本区域中的文字,用两个字节的内存存储,用一个char表示,而辅助区域中的文字用4个字节存储,因此辅助区域中的就要用两个char来表示了(表一种蓝色底就是辅助区域中的文字)。一个文字的unicode编码,在Java中统一用codePoint(代码点)这个概念。
中文和日文、韩文一样是表意文字,在Unicode中,中日韩三国(东亚地区)的文字是统一编码的。CJK代表的就是中日韩。在这里,我把这3中文字,都作为汉字处理了。(日语和韩语可能就是从汉语中衍生的吧!)
汉字在Unicode中的分布大致如下表:
首字编码 | 尾字编码 | 个数 | |
基本汉字 | U4E00 | U9FBF | 20928 |
异性字 | UF900 | UFAFF | 512 |
扩展A | U3400 | U4D8F | 512 |
扩展B | U20000 | U2A6DF | 42720 |
补充 | U2F800 | U2FA1F | 544 |
其他 | ... |
在这些编码区间,有些编码是保留的。
GB2312编码
GB2312是中华人民共和国最早的计算机汉字编码方式。大概有6000多个汉字,这些汉字是按拼音顺序编码的。这6000多个汉字都是简体中文字。
GBK编码
GB2312的扩展,并兼容GB2312。扩展后的汉字大概有2万多个,其中有简体汉字也有繁体汉字。
拼音排序
拼音有好几种方式,其中最主要的是中华人民共和国的汉语拼音 Chinese Phonetic。对汉字的排序有两种:一种是宽松的,能够按拼音排序最常用的汉字,另一种是严格的,能够按拼音排序绝大部分大部分汉字。
宽松的拼音排序法
原理:汉字最早是GB2312编码,收录了六千多个汉字,是按拼音排序的,编码是连续的。 后来出现了GBK编码,对GB2312进行了扩展,到了两万多汉字,并且兼容GB2312,也就是说GB2312中的汉字编码是原封不动搬到GBK中的(在GBK编码中[B0-D7]区中)。
如果我们只关心这6000多个汉字的顺序,就可以用下面的方法实现汉字宽松排序。
/**
* @author Jeff
*
* Copyright (c) 复制或转载本文,请保留该注释。
*/
package chinese.utility;
import java.text.Collator;
import java.util.Comparator;
import java.util.Locale;
public class PinyinSimpleComparator implements Comparator<String> {
public int compare(String o1, String o2) {
return Collator.getInstance(Locale.CHINESE).compare(o1, o2);
}
}
在对[孙, 孟, 宋, 尹, 廖, 张, 徐, 昆, 曹, 曾,怡]这几个汉字排序,结果是:[曹, 昆, 廖, 孟, 宋, 孙, 徐, 尹, 曾, 张, 怡]。最后一个 怡 有问题,不该排在最后的。
注意:这个程序有两个不足
- 由于gb2312中的汉字编码是连续的,因此新增加的汉字不可能再按照拼音顺序插入到已有的gb2312编码中,所以新增加的汉字不是按拼音顺序排的。
- 同音字比较的结果不等于0 。
下面的测试代码可以证明
/**
* @author Jeff
*
* Copyright (c) 复制或转载本文,请保留该注释。
*/
/**
* 非常用字(怡)
*/
@Test
public void testNoneCommon() {
Assert.assertTrue(comparator.compare("怡", "张") > 0);
}
/**
* 同音字
*/
@Test
public void testSameSound() {
Assert.assertTrue(comparator.compare("怕", "帕") != 0);
}
严格的拼音排序法
为了解决宽松的拼音的两点不足,可以通过实现汉语拼音的函数来解决。goolge下看到sf上有个pinyin4j的项目,可以解决这个问题,pinyin4j的项目地址是:http://pinyin4j.sourceforge.net/。
实现代码:
/**
* @author Jeff
*
* Copyright (c) 复制或转载本文,请保留该注释。
*/
package chinese.utility;
import java.util.Comparator;
import net.sourceforge.pinyin4j.PinyinHelper;
public class PinyinComparator implements Comparator<String> {
public int compare(String o1, String o2) {
for (int i = 0; i < o1.length() && i < o2.length(); i++) {
int codePoint1 = o1.charAt(i);
int codePoint2 = o2.charAt(i);
if (Character.isSupplementaryCodePoint(codePoint1)
|| Character.isSupplementaryCodePoint(codePoint2)) {
i++;
}
if (codePoint1 != codePoint2) {
if (Character.isSupplementaryCodePoint(codePoint1)
|| Character.isSupplementaryCodePoint(codePoint2)) {
return codePoint1 - codePoint2;
}
String pinyin1 = pinyin((char) codePoint1);
String pinyin2 = pinyin((char) codePoint2);
if (pinyin1 != null && pinyin2 != null) { // 两个字符都是汉字
if (!pinyin1.equals(pinyin2)) {
return pinyin1.compareTo(pinyin2);
}
} else {
return codePoint1 - codePoint2;
}
}
}
return o1.length() - o2.length();
}
/**
* 字符的拼音,多音字就得到第一个拼音。不是汉字,就return null。
*/
private String pinyin(char c) {
String[] pinyins = PinyinHelper.toHanyuPinyinStringArray(c);
if (pinyins == null) {
return null;
}
return pinyins[0];
}
}
测试:
/**
* @author Jeff
*
* Copyright (c) 复制或转载本文,请保留该注释。
*/
package chinese.utility.test;
import java.util.Comparator;
import org.junit.Assert;
import org.junit.Test;
import chinese.utility.PinyinComparator;
public class PinyinComparatorTest {
private Comparator<String> comparator = new PinyinComparator();
/**
* 常用字
*/
@Test
public void testCommon() {
Assert.assertTrue(comparator.compare("孟", "宋") < 0);
}
/**
* 不同长度
*/
@Test
public void testDifferentLength() {
Assert.assertTrue(comparator.compare("他奶奶的", "他奶奶的熊") < 0);
}
/**
* 和非汉字比较
*/
@Test
public void testNoneChinese() {
Assert.assertTrue(comparator.compare("a", "阿") < 0);
Assert.assertTrue(comparator.compare("1", "阿") < 0);
}
/**
* 非常用字(怡)
*/
@Test
public void testNoneCommon() {
Assert.assertTrue(comparator.compare("怡", "张") < 0);
}
/**
* 同音字
*/
@Test
public void testSameSound() {
Assert.assertTrue(comparator.compare("怕", "帕") == 0);
}
/**
* 多音字(曾)
*/
@Test
public void testMultiSound() {
Assert.assertTrue(comparator.compare("曾经", "曾迪") > 0);
}
}
我的这样严格的拼音排序还是有有待改进的地方,看上面测试代码的最后一个测试,就会发现:程序不会根据语境来判断多音字的拼音,仅仅是简单的取多音字的第一个拼音。
笔画排序
要按笔画排序,就要实现笔画比较器。
class StokeComparator implements Comparator<String>
如果有个方法可以求得汉字的笔画数,上面的功能就很容易实现。如何求一个汉字的笔画数?最容易想到的就是查表法。建一个汉字笔画数表,如:
汉字 | Unicode编码 | 笔画数 |
一 | U4E00 | 1 |
二 | U4E8C | 2 |
龍 | U9F8D | 16 |
... | ... | ... |
如果是连续的、按unicode编码排好顺序的表,实际存储在笔画数表中的只需最后一列就够了。
那如何建这个表呢?这个表存储在哪里?
建汉字笔画数表
现在大多数系统还只能支持Unicode中的基本汉字那部分汉字,编码从U9FA6-U9FBF。所以我们只建这部分汉字的笔画表。汉字笔画数表,我们可以按照下面的方法生成:
- 用java程序生成一个文本文件(Chinese.csv)。包括所有的从U9FA6-U9FBF的字符的编码和文字。利用excel的按笔画排序功能,对Chinese.csv文件中的内容排序。
- 编写Java程序分析Chinese.csv文件,求得笔画数, 生成ChineseStroke.csv。矫正笔画数,重新按汉字的Unicode编码对ChineseStroke.csv文件排序。
- 只保留ChineseStroke.csv文件的最后一列,生成Stroke.csv。
在这里下载上面3个步骤生成的3个文件。
生成Chinese.csv的Java程序
/**
* @author Jeff
*
* Copyright (c) 复制或转载本文,请保留该注释。
*/
package chinese.utility.preface;
import java.io.IOException;
import java.io.PrintWriter;
public class ChineseCoder {
public static void main(String[] args) throws IOException {
PrintWriter out = new PrintWriter("Chinese.csv");
// 基本汉字
for(char c = 0x4E00; c <= 0x9FA5; c++) {
out.println((int)c + "," + c);
}
out.flush();
out.close();
}
}
初始化笔画数
从Excel排序过后的Chinese.csv文件来看,排好序的文件还是有一定规律的。在文件的第9行-12行可以看出:逐行扫描的时候,当unicode会变小了,笔画数也就加1。
20059,乛
20101,亅
19969,丁
19970,丂
用下面的Java程序分析吧。
/**
* @author Jeff
*
* Copyright (c) 复制或转载本文,请保留该注释。
*/
package chinese.utility.preface;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Scanner;
public class Stroke {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
Scanner in = new Scanner(new File("Chinese.csv"));
PrintWriter out = new PrintWriter("ChineseStroke.csv");
String oldLine = "999999";
int stroke = 0;
while (in.hasNextLine()) {
String line = in.nextLine();
if (line.compareTo(oldLine) < 0) {
stroke++;
}
oldLine = line;
out.println(line + "," + stroke);
}
out.flush();
out.close();
in.close();
}
}
上面用的这个规律有问题吗?有问题,从ChineseStroke.csv文件抽取最后几个汉字就发现,笔画数不对。为什么呢?
- 笔画数可能不是连续的。
- n+1笔画数的最小Unicode码可能比n笔画数的最大Unicode码要大
我们要人工核对ChineseStroke文件,但只要核对在笔画变化的那几个汉字的笔画数。最后,我发现,只有笔画数多于30的少数几个汉字的笔画数不对。核对并矫正笔画数后,用Excel按Unicode重新排序,去掉汉字和Unicode两列,只保留笔画数那列,得到Stroke.csv文件。
求得笔画数的方法和笔画比较器方法
求得笔画数的方法测试代码:
/**
* @author Jeff
*
* Copyright (c) 复制或转载本文,请保留该注释。
*/
package chinese.utility.test;
import static org.junit.Assert.assertEquals;
import org.junit.Before;
import org.junit.Test;
import chinese.utility.Chinese;
public class StrokeTest {
Chinese chinese;
@Before
public void setUp() {
chinese = new Chinese();
}
@Test
public void testStroke() {
assertEquals(1, chinese.stroke('一'));
}
@Test
public void testStroke2() {
assertEquals(2, chinese.stroke('二'));
}
@Test
public void testStroke16() {
assertEquals(16, chinese.stroke('龍'));
}
@Test
public void testStrokeABC() {
assertEquals(-1, chinese.stroke('a'));
}
}
求得笔画数的方法代码
/**
* @author Jeff
*
* Copyright (c) 复制或转载本文,请保留该注释。
*/
package chinese.utility;
import java.util.Comparator;
public class StrokeComparator implements Comparator<String> {
public int compare(String o1, String o2) {
Chinese chinese = new Chinese();
for (int i = 0; i < o1.length() && i < o2.length(); i++) {
int codePoint1 = o1.codePointAt(i);
int codePoint2 = o2.codePointAt(i);
if (codePoint1 == codePoint2)
continue;
int stroke1 = chinese.stroke(codePoint1);
int stroke2 = chinese.stroke(codePoint2);
if (stroke1 < 0 || stroke2 < 0) {
return codePoint1 - codePoint2;
}
if (stroke1 != stroke2) {
return stroke1 - stroke2;
}
}
return o1.length() - o2.length();
}
}
笔画比较器测试
/**
* @author Jeff
*
* Copyright (c) 复制或转载本文,请保留该注释。
*/
package chinese.utility.test;
import java.util.Comparator;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import chinese.utility.StrokeComparator;
public class StrokeComparatorTest {
private Comparator<String> comparator;
@Before
public void setUp() {
comparator = new StrokeComparator();
}
/**
* 相同笔画数
*/
@Test
public void testCompareEquals() {
Assert.assertTrue(comparator.compare("一", "丨") == 0);
}
/**
* 不同笔画数
*/
@Test
public void testCompare() {
Assert.assertTrue(comparator.compare("一", "二") < 0);
Assert.assertTrue(comparator.compare("唔", "马") > 0);
}
/**
* 长度不同
*/
@Test
public void testCompareDefficultLength() {
Assert.assertTrue(comparator.compare("二", "二一") < 0);
}
/**
* 非汉字的比较
*/
@Test
public void testABC() {
Assert.assertTrue(comparator.compare("一", "a") > 0);
Assert.assertTrue(comparator.compare("a", "b") < 0);
}
}
笔画比较器
/**
* @author Jeff
*
* Copyright (c) 复制或转载本文,请保留该注释。
*/
package chinese.utility.test;
import java.util.Comparator;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import chinese.utility.StrokeComparator;
public class StrokeComparatorTest {
private Comparator<String> comparator;
@Before
public void setUp() {
comparator = new StrokeComparator();
}
/**
* 相同笔画数
*/
@Test
public void testCompareEquals() {
Assert.assertTrue(comparator.compare("一", "丨") == 0);
}
/**
* 不同笔画数
*/
@Test
public void testCompare() {
Assert.assertTrue(comparator.compare("一", "二") < 0);
Assert.assertTrue(comparator.compare("唔", "马") > 0);
}
/**
* 长度不同
*/
@Test
public void testCompareDefficultLength() {
Assert.assertTrue(comparator.compare("二", "二一") < 0);
}
/**
* 非汉字的比较
*/
@Test
public void testABC() {
Assert.assertTrue(comparator.compare("一", "a") > 0);
Assert.assertTrue(comparator.compare("a", "b") < 0);
}
}
评论
very very nice ....
发表评论
-
一个简单的权重百分比算法
2017-07-31 15:24 2021import java.util.Arrays; pub ... -
帮你大致定位到现场导致LOAD飙升的JVM线程
2016-07-19 08:59 1572帮你大致定位到现场导致LOAD飙升的JVM线程 大家都有过遇到 ... -
字符编码格式转换
2010-07-12 11:40 1339package com.yohn.encoding.con ... -
文件操作
2009-11-06 15:59 1296package com.yohn.fileupload; i ... -
java中小数点问题
2009-03-30 20:13 1078让头痛的小数问题.昨天在项目中出现小数精度问题,弄了好久,找到 ... -
xfire+webservice
2009-03-04 11:51 1454下面我们开始在eclipse中间类开发webservice。有 ... -
关于static与final
2009-02-20 20:34 171public class HibernateSessionF ... -
讨论一下java跳转语句
2009-02-18 18:20 1341请教一下大字这个语句: public class Demo { ... -
Java集成开发工具
2009-02-17 22:28 1523JBuilder改旗易帜 Java IDE市场重洗牌 ... -
做二次开发
2009-01-03 16:22 812今天和同学聊天,有想法去做做二次开发!可是又不知道如何进行 ... -
Myeclipse6或6.5反编译工具安装
2008-12-31 19:18 5962jad是java的反编译工具,是命令行执行,反编译出来的源文件 ... -
Java和JSP编程应该注意的六个常见问题
2008-12-17 23:36 7451.对应String类型的对象使用println( ... -
JAVA全角和半角的转换
2008-11-20 20:00 1298public class change { pu ... -
关于Sun将基于OpenJDK 7生成OpenJDK 6
2008-11-20 19:47 2055Sun将基于OpenJDK 7生成Open ... -
查找出[url][url]中间的数据
2008-11-19 13:47 1030各位兄弟!今天突然遇到了一个这样的问题!就是博客中的链接问 ... -
eclipse 插件大全
2008-11-19 02:35 21347eclipse插件大全介绍,以及下载地址 开源中心 http: ... -
java中 int 转 byte 的规律
2008-11-18 23:17 5326一). a(-|+)256=c; 如果a为正数那么使用a-25 ... -
听说要重复执行一个方法的时候Timer类不好
2008-11-15 23:06 1507各位同仁们!听一个项目经理讲要重复执行一段代码的时候最好少 ... -
jbmp整个调用流程
2008-11-15 22:50 1372package com.test; import java.u ... -
发现java api文档5和6的一个不区别
2008-11-13 11:31 1256刚刚用到ArrayDeque类时使用j2sdk_6_api ...
相关推荐
默认情况下,Java使用自然排序,即按照字符串的Unicode值进行排序,这对于英文字符和数字来说通常是合适的,但对于中文字符则不是我们期望的排序方式。 为了实现中文、数字和字母的排序,我们需要创建一个`...
在Java中,可以使用`java.util.Comparator`接口自定义比较规则,根据笔画数对`List<String>`类型的汉字列表进行排序。此外,`java.text.Normalizer`类可以帮助处理Unicode编码,确保笔画计算的准确性。 总的来说,...
这些标签强调了该话题的特定技术点,即使用Java语言对中文字符进行笔画计数并依据笔画数量进行排序。 在提供的压缩包文件中,我们有三个文件: 1. `strokesort2.jar`:这是一个Java可执行文件,包含编译后的代码,...
今天,我们将探讨如何使用 Java 语言来实现中文字符按 Unicode 排序。 在 Java 中,String 类提供了默认的比较方案,即使用 compareTo 方法。然而,这种方法不能正确地处理中文字符。例如,我们可以使用以下代码来...
利用java对基本汉字(unicode编码4E00-9FA5)进行笔画排序 资源更新查看:https://blog.csdn.net/u013271384/article/details/76549368
以下是对Java中编码方式和Unicode的知识点总结: 1. 基本概念 - bit:计算机存储的最小单位,只能是0或者1。 - byte:一个字节是8个bit,计算机表示的基本单位。 - 字节换算:1KB(千字节)= 1024字节,1MB(兆字节...
首先,我们要明白在Java中,默认的字符串排序是基于Unicode编码的,这可能会导致中文字符与英文字符混合排序时出现问题。例如,英文字符通常会排在中文字符前面,因为它们的Unicode值更低。为了解决这个问题,我们...
在Java编程语言中,对字符串中的字符进行a到z排序是一项常见的操作,特别是在处理文本数据或需要对字母顺序排列的场景。本知识点将详细讲解如何实现这个功能。 首先,我们需要理解字符串在Java中的本质。在Java中,...
在Java编程语言中,对中文字符串进行排序是一个相对复杂的问题,因为中文字符的排序不能简单地按照Unicode编码顺序来处理。通常,我们需要考虑汉字的拼音或者笔画等属性来进行排序。这里我们将详细介绍如何使用`...
利用java对基本汉字(unicode编码4E00-9FA5)进行笔画排序 资源更新查看:https://blog.csdn.net/u013271384/article/details/76549368
汉字通常使用Unicode编码,如GBK或UTF-8,每个汉字占用2至4个字节,而数字是字符型数据,如'0'到'9',在ASCII码中每个数字占用一个字节。这就意味着在比较时,如果不进行特殊处理,数字会按照其字典顺序(ASCII值)...
中文Unicode编码表通常按照汉字的笔画、部首或者四角号码等排序,方便用户查找。其中,每一个汉字的Unicode码点可以转换为16进制表示,例如“我”字的Unicode码点是U+6211,对应的16进制值是4E61。在实际应用中,16...
在Java编程语言中,对用户名进行比较排序是一个常见的任务,特别是在开发用户管理系统或者任何涉及到用户数据展示的应用中。这个任务通常涉及到字符串的比较和排序,Java提供了强大的工具来实现这一功能。下面我们将...
在Java中,字符串的比较默认基于Unicode编码,这可能不符合中文的排序习惯。为了实现中文的自然顺序排序,我们需要自定义比较器。 1. 实现Comparable接口: 如果你的对象包含一个表示中文的字符串字段,可以在类中...
例如,可以创建一个表并插入数据,然后使用`ORDER BY`语句配合`collate`关键字来实现按拼音或笔画对汉字进行排序。在示例1中,通过`collate Chinese_PRC_CS_AS_KS_WS`,我们让表中的名字按照拼音顺序排列。而在示例2...
对于中文,我们需要使用支持中文字符集(如UTF-8)的Unicode排序规则。 在SQLite中,我们可以创建一个自定义的Collation(排序规则)来处理中文排序。以下是一种简单的实现方式: 1. 创建自定义Collation: 在...
这个任务涉及到字符编码、Unicode和中文字符处理。以下是对这一知识点的详细阐述: 1. **字符编码**:汉字在计算机中存储和处理时需要转换成特定的编码形式,常见的有GB2312、GBK、GB18030以及Unicode(UTF-8)。...
这个问题通常涉及到字符编码和Unicode排序规则。 解决DisplayTag中文排序问题的关键在于理解Java的字符串比较机制。Java中的`String`对象在进行比较时,默认是基于Unicode的字典顺序,这可能导致中文字符按照其...
对于“按照字母顺序进行排序”,通常指的是对字符或字符串序列进行升序排列,遵循ASCII码或Unicode编码标准。 二、ASCII码与Unicode ASCII码(美国信息交换标准代码)是一种基于拉丁字母的一套电脑编码系统,最初...
中文排序涉及到中文字符编码(如UTF-8)和Unicode码点。在Android中,如果不特殊处理,中文字符可能会按照Unicode码点顺序排序,这可能与我们的直观排序不符。因此,我们需要自定义排序规则,例如使用Pinyin4j库将...