对于包含汉字的字符串来说,排序的方式主要有两种:一种是拼音,一种是笔画。

本文就讲述如何实现按笔划排序的比较器(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。所以我们只建这部分汉字的笔画表。汉字笔画数表,我们可以按照下面的方法生成:

  1. 用java程序生成一个文本文件(Chinese.csv)。包括所有的从U9FA6-U9FBF的字符的编码和文字。利用excel的按笔画排序功能,对Chinese.csv文件中的内容排序。
  2. 编写Java程序分析Chinese.csv文件,求得笔画数, 生成ChineseStroke.csv。矫正笔画数,重新按汉字的Unicode编码对ChineseStroke.csv文件排序。
  3. 只保留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)按笔划排序的更多相关文章

  1. Java汉字排序(2)按拼音排序

    对于包含汉字的字符串来说,排序的方式主要有两种:一种是拼音,一种是笔画. 本文就讲述如何实现按拼音排序的比较器(Comparator). 作者:Jeff 发表于:2007年12月21日 11:27 最 ...

  2. Java汉字排序(1)排序前要了解的知识(数组和list的排序接口)

    对于包含汉字的字符串来说,排序的方式主要有两种:一种是拼音,一种是笔画. 本文就讲述如何实现按拼音排序的比较器(Comparator). 作者:Jeff 发表于:2007年12月21日 11:27 最 ...

  3. Java面试宝典系列之基础排序算法

    本文就是介绍一些常见的排序算法.排序是一个非常常见的应用场景,很多时候,我们需要根据自己需要排序的数据类型,来自定义排序算法,但是,在这里,我们只介绍这些基础排序算法,包括:插入排序.选择排序.冒泡排 ...

  4. Java常见排序算法之Shell排序

    在学习算法的过程中,我们难免会接触很多和排序相关的算法.总而言之,对于任何编程人员来说,基本的排序算法是必须要掌握的. 从今天开始,我们将要进行基本的排序算法的讲解.Are you ready?Let ...

  5. Java比较器对数组,集合排序一

    数组排序非常简单,有前辈们的各种排序算法,再加上Java中强大的数组辅助类Arrays与集合辅助类Collections,使得排序变得非常简单,如果说结合比较器Comparator接口和Collato ...

  6. java结构与算法之选择排序

    一 .java结构与算法之选择排序(冒择路兮快归堆) 什么事选择排序:从一组无序数据中选择出中小的的值,将该值与无序区的最左边的的值进行交换. 简单的解释:假设有这样一组数据 12,4,23,5,找到 ...

  7. 使用C语言和Java分别实现冒泡排序和选择排序

    经典排序算法--冒泡和选择排序法 Java实现冒泡排序 基本思想是,对相邻的元素进行两两比较,顺序相反则进行交换,这样,每一趟会将最小或最大的元素放到顶端,最终达到完全有序,首先看个动图: 我们要清楚 ...

  8. 【java多线程系列】java内存模型与指令重排序

    在多线程编程中,需要处理两个最核心的问题,线程之间如何通信及线程之间如何同步,线程之间通信指的是线程之间通过何种机制交换信息,同步指的是如何控制不同线程之间操作发生的相对顺序.很多读者可能会说这还不简 ...

  9. 我们一起来排序——使用Java语言优雅地实现常用排序算法

    破阵子·春景 燕子来时新社,梨花落后清明. 池上碧苔三四点,叶底黄鹂一两声.日长飞絮轻. 巧笑同桌伙伴,上学径里逢迎. 疑怪昨宵春梦好,元是今朝Offer拿.笑从双脸生. 排序算法--最基础的算法,互 ...

随机推荐

  1. 《APUE》第五章笔记

    第五章具体介绍了标准I/O库的各种细节,要是一一列出来,有费精力且可能列不全,故只讲平常多用到的.标准输入输出是由一大批函数组成的. 要记住,标准输入输出是有缓冲的,就是当缓冲区的数据满了的时候,才会 ...

  2. 51nod1417 天堂里的游戏

    ---恢复内容开始--- 1417 天堂里的游戏 基准时间限制:1 秒 空间限制:131072 KB 分值: 10 难度:2级算法题  收藏  关注 多年后,每当Noder看到吉普赛人,就会想起那个遥 ...

  3. PHP实现冒泡算法

    <?php //php函数:count($arr)返回array的数值总数. function bubble_sort($arr){ for ($i = 6;$i > 0;$i --){ ...

  4. PHP curl 模拟登录

    //提交数据,生成cookie,将cookie保存在临时目录下//在指定目录中建立一个具有唯一文件名的文件.如果该目录不存在,tempnam() 会在系统临时目录中生成一个文件,并返回其文件名 $co ...

  5. Java学习笔记:语言基础

    Java学习笔记:语言基础 2014-1-31   最近开始学习Java,目的倒不在于想深入的掌握Java开发,而是想了解Java的基本语法,可以阅读Java源代码,从而拓展一些知识面.同时为学习An ...

  6. Spark小课堂Week5 Scala初探

    Spark小课堂Week5 Scala初探 Scala是java威力加强版. 对Java的改进 这里会结合StreamingContext.scala这个代码说明下对Java的改进方面. 方便测试方式 ...

  7. Python数据结构——二叉树的实现

    1. 二叉树 二叉树(binary tree)中的每个节点都不能有多于两个的儿子. 1.1 二叉树列表实现 如上图的二叉树可用列表表示: tree=['A', #root ['B', #左子树 ['D ...

  8. Hibernate 关联 set 和 list 对比

    这里考虑的不是hibernate配置文件相关的list和set.而是实际注入的java集合. 1.就单纯java集合的效率对比 list要比set效率高,因为set是把元素存在map的key所在位置上 ...

  9. linux grep、find 命令详解

    grep1.作用grep命令可以指定文件中搜索特定的内容,并将含有这些内容的行标准输出.grep全称是Global Regular Expression Print,表示全局正则表达式版本,它的使用权 ...

  10. TWaver3D入门探索——3D拓扑图之绽放的小球花

    这样一簇绚烂丰满艳丽多姿的3D小球花,要多少代码才能完成?其实不足百行,您信吗?下面咱就看一下具体实现过程,让您分分钟学会用TWaver HTML5制作3D拓扑图. 搭建3D空间 首先为花簇的绽放建一 ...