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拿.笑从双脸生. 排序算法--最基础的算法,互 ...
随机推荐
- 获取当前<script>节点
/* get current JavaScript dom object. */ var all_js = document.getElementsByTagName("script&quo ...
- DevExpress gridView 小结(一)
一:第一列显示行号 CustomDrawRowIndicator this.gridViewDevice.IndicatorWidth = 40; this.gridViewDevice.Custo ...
- jquery 点击查看,收起特效
<div class="all"> <p><a href="javascript:;" id="onvk"&g ...
- PHP7 新特性 简介
整理了一些常用的新特性,欢迎点赞!!! 新增操作符 1.?? $username = $_GET['user'] ?? ''; $username = isset($_GET['user']) ? $ ...
- DrawWindowFrame
extern void DrawWindowFrame(HWND hWnd)//画窗口边框 { RECT rc; HWND DeskHwnd = ::GetDesktopWindow(); //取得桌 ...
- Virtual Box中 CentOS双网卡设置
Virtual Box中 CentOS双网卡设置: 在Virtual Box中安装CentOS x86-64 6.4(final),配置了双网卡,eth0 为桥接模式 , eth1为内网模式 ...
- Wpf 简单制作自己的窗体样式(2)
上一篇blog讲了制作简单的样式的窗体,对于一个传统的窗体,不仅仅可以拖动,和关闭操作.还具有最大化.最小化.隐藏,以及改变窗体的大小等.这篇blog就是对上篇的补充,完善窗体的改变大小和最大化最小化 ...
- 五、mysql存储引擎
show variable like 'table_type'; 显示系统默认存储引擎 show engine\G 显示系统支持存储殷勤 =============================== ...
- 【BZOJ2428】[HAOI2006]均分数据
Description 已知N个正整数:A1.A2.…….An .今要将它们分成M组,使得各组数据的数值和最平均,即各组的均方差最小.均方差公式如下: ,其中σ为均方差,是各组数据和的平均值,xi为第 ...
- c# DirectoryInfo类 详解
DirectoryInfo类和Directory类之间的关系与FileInfo类和File类之间的关系十分类似.下面介绍一下DirectoryInfo类的常用属性. DirectoryInfo类的常用 ...