Java汉字排序(3)按笔划排序
对于包含汉字的字符串来说,排序的方式主要有两种:一种是拼音,一种是笔画。
本文就讲述如何实现按笔划排序的比较器(Comparator)。
作者:Jeff 发表于:2007年12月21日 11:27 最后更新于: 2007年12月21日 12:38
版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本版权声明。
http://www.blogjava.net/jeff-lau/archive/2007/12/21/169257.html
笔画排序
要按笔画排序,就要实现笔画比较器。
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 = "";
int stroke = ;
while (in.hasNextLine()) {
String line = in.nextLine();
if (line.compareTo(oldLine) < ) {
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(, chinese.stroke('一'));
} @Test
public void testStroke2() {
assertEquals(, chinese.stroke('二'));
} @Test
public void testStroke16() {
assertEquals(, chinese.stroke('龍'));
} @Test
public void testStrokeABC() {
assertEquals(-, 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 = ; 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 < || stroke2 < ) {
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("一", "丨") == );
} /**
* 不同笔画数
*/
@Test
public void testCompare() {
Assert.assertTrue(comparator.compare("一", "二") < );
Assert.assertTrue(comparator.compare("唔", "马") > );
} /**
* 长度不同
*/
@Test
public void testCompareDefficultLength() {
Assert.assertTrue(comparator.compare("二", "二一") < );
} /**
* 非汉字的比较
*/
@Test
public void testABC() {
Assert.assertTrue(comparator.compare("一", "a") > );
Assert.assertTrue(comparator.compare("a", "b") < );
}
}
笔画比较器
/**
* @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("一", "丨") == );
} /**
* 不同笔画数
*/
@Test
public void testCompare() {
Assert.assertTrue(comparator.compare("一", "二") < );
Assert.assertTrue(comparator.compare("唔", "马") > );
} /**
* 长度不同
*/
@Test
public void testCompareDefficultLength() {
Assert.assertTrue(comparator.compare("二", "二一") < );
} /**
* 非汉字的比较
*/
@Test
public void testABC() {
Assert.assertTrue(comparator.compare("一", "a") > );
Assert.assertTrue(comparator.compare("a", "b") < );
}
}
其他程序的汉字排序
Microsoft在这方面做得比较好。如Sql server 2000,Word和Excel都能按拼音和笔画排序。而Oracle只能是采取宽松拼音排序法。
Java汉字排序(3)按笔划排序的更多相关文章
- Java汉字排序(2)按拼音排序
对于包含汉字的字符串来说,排序的方式主要有两种:一种是拼音,一种是笔画. 本文就讲述如何实现按拼音排序的比较器(Comparator). 作者:Jeff 发表于:2007年12月21日 11:27 最 ...
- Java汉字排序(1)排序前要了解的知识(数组和list的排序接口)
对于包含汉字的字符串来说,排序的方式主要有两种:一种是拼音,一种是笔画. 本文就讲述如何实现按拼音排序的比较器(Comparator). 作者:Jeff 发表于:2007年12月21日 11:27 最 ...
- Java面试宝典系列之基础排序算法
本文就是介绍一些常见的排序算法.排序是一个非常常见的应用场景,很多时候,我们需要根据自己需要排序的数据类型,来自定义排序算法,但是,在这里,我们只介绍这些基础排序算法,包括:插入排序.选择排序.冒泡排 ...
- Java常见排序算法之Shell排序
在学习算法的过程中,我们难免会接触很多和排序相关的算法.总而言之,对于任何编程人员来说,基本的排序算法是必须要掌握的. 从今天开始,我们将要进行基本的排序算法的讲解.Are you ready?Let ...
- Java比较器对数组,集合排序一
数组排序非常简单,有前辈们的各种排序算法,再加上Java中强大的数组辅助类Arrays与集合辅助类Collections,使得排序变得非常简单,如果说结合比较器Comparator接口和Collato ...
- java结构与算法之选择排序
一 .java结构与算法之选择排序(冒择路兮快归堆) 什么事选择排序:从一组无序数据中选择出中小的的值,将该值与无序区的最左边的的值进行交换. 简单的解释:假设有这样一组数据 12,4,23,5,找到 ...
- 使用C语言和Java分别实现冒泡排序和选择排序
经典排序算法--冒泡和选择排序法 Java实现冒泡排序 基本思想是,对相邻的元素进行两两比较,顺序相反则进行交换,这样,每一趟会将最小或最大的元素放到顶端,最终达到完全有序,首先看个动图: 我们要清楚 ...
- 【java多线程系列】java内存模型与指令重排序
在多线程编程中,需要处理两个最核心的问题,线程之间如何通信及线程之间如何同步,线程之间通信指的是线程之间通过何种机制交换信息,同步指的是如何控制不同线程之间操作发生的相对顺序.很多读者可能会说这还不简 ...
- 我们一起来排序——使用Java语言优雅地实现常用排序算法
破阵子·春景 燕子来时新社,梨花落后清明. 池上碧苔三四点,叶底黄鹂一两声.日长飞絮轻. 巧笑同桌伙伴,上学径里逢迎. 疑怪昨宵春梦好,元是今朝Offer拿.笑从双脸生. 排序算法--最基础的算法,互 ...
随机推荐
- 图片延迟加载库Layzr
<!DOCTYPE html> <html> <head> <title>Layzr Demo</title> <script src ...
- Dapper full example
Skip to content Sign up Sign in This repository Explore Features Enterprise Blog Watch Star , Fork S ...
- PySide 简易教程<一>-------Hello PySide
PySide 是一个python绑定的跨平台GUI Qt库.目前,支持Python的Qt库有两个PyQt和PySide.PySide是一个免费的软件,与PyQt不同之处在于使用了LGPL,允许PySi ...
- FPGA初学心得
有三种方法在模块中产生逻辑:1.使用连续赋值语句“assign”:2.用实例元件 3.用“always”块.所以在always块中赋值不能使用assign,而是直接给变量赋值就行. reg与wire的 ...
- web.xml中JSP配置及 EL表达式
web.xml 中JSP配置.servlet配置 及 EL表达式 [摘要] servlet 基本配置 <servlet> <servlet-name>LoginServlet& ...
- Eclipse中propedit插件安装(解决property中文问题)
Eclipse Help--Install New Software... Add... propedit -- http://propedit.sourceforge.jp/eclipse/up ...
- Oracle “CONNECT BY” 使用
Oracle “CONNECT BY” 使用 功能说明: 语法结构如下: [ START WITH condition ] CONNECT BY [ NOCYCLE ] condition 说明: 1 ...
- C++ 虚函数表解析(转载)
转载自:陈皓 http://blog.csdn.net/haoel/article/details/1948051/ 前言 C++中的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型 ...
- jQuery 点击按钮刷新页面
//页面加载时绑定按钮点击事件 $(function () { $("#按钮id").click(function () { refresh(); }); }); //点击按钮调用 ...
- /****************** Attributes ********************/
/*预定义字符属性的文本.如果钥匙不在字典,然后使用默认值,如下所述. */ 以下属性是IOS6的 NSVerticalGlyphFormAttributeName NS_AVAILABLE_IOS( ...