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拿.笑从双脸生. 排序算法--最基础的算法,互 ...
随机推荐
- 在Mac OS X中使用VIM开发STM32(4)
本文原创于http://www.cnblogs.com/humaoxiao,非法转载者请自重! 在上三篇文章中,我们基本搭建好了开发STM32的IDE环境,当然vim.ctags.tagl ...
- VS2010水晶报表的添加与使用
最近在学习VS2010水晶报表,发现原先安装的VS2010旗舰版没有 Crystal Report Viewer 控件,网上搜索一下发现要安装一个插件----CRforVS_13_0, 于是下载安装: ...
- JavaScript 高级程序设计 目录
为什么会写这个学习教程呢??因为一直以来,学习JavaScript都没有系统的学过,用什么学什么,所以今天开始,重新把JavaScript系统的学一遍!(本人也是菜鸟一枚,语文水平也还是小学程度,看得 ...
- TDBAdvGrid 只读状态下复制功能
DataSource1.AutoEdit := false;
- Spark Streaming揭秘 Day29 深入理解Spark2.x中的Structured Streaming
Spark Streaming揭秘 Day29 深入理解Spark2.x中的Structured Streaming 在Spark2.x中,Spark Streaming获得了比较全面的升级,称为St ...
- 深入理解jsavascript的作用域
一. JavaScript声明提前 在JavaScript中如果不创建变量,直接去使用,则报错: console.log(xxoo); // 报错:Uncaught ReferenceError: x ...
- WPF中利用DynamicDataDisplay快速实现示波器功能
DynamicDataDisplay控件是一个功能很强的绘图工具,除了能生成曲线外,还有很多其他功能,具体见http://dynamicdatadisplay.codeplex.com/.这里你也能下 ...
- Mapped Statements collection does not contain value for
这是由pojo的映射文件的命名空间引起的错误. 按照以下格式即可:命名空间中一定要含有mapper.xxMapper这样的格式,否则出现以上错误. <?xml version="1.0 ...
- Maven系列--"maven-compiler-plugin"的使用、Maven之Surefire插件
一."maven-compiler-plugin"的使用 http://my.oschina.net/poorzerg/blog/206856 二.Maven之Surefire插件 ...
- js中replace的正则替换
temp: video":"\t<ul class=\"g-list tabview-cont on\">\t\r\n\t\t<li clas ...