ChinaUnix.net 首页 | 博客 | Linux | 论坛 | 人才 | 培训 | 知识库 | 资料 | 读书 | 手册 | 精华 | 下载 | 沙龙 | 搜索
Linux首页 | Linux论坛 | 论坛精华 | 开源新闻 | 技术文章 | 专题专栏 | 新手指南 | 迁移方案 | 产品方案 | 开源项目 | 开源图书 | 软件下载 | 人才招聘 | Linux博客
  搜索

  产品与方案
·中科红旗全面打造现代化邮政体系
·红旗助力“网上审批服务” 推动电子政务
·红旗正版化开创呼和浩特网吧建设新起点
·红旗Linux助信息产业部邮件服务器“快跑”
·中标普华Linux 为电子政务信息化保驾护航
·中标普华Linux助力基金产业
·中标普华Office率先支持UOF标准
·中标普华邮件系统助力西藏政府信息化建设
·红旗Linux助力国库集中支付系统改革
·红旗助中信卫星 掀起GIS通信应用风暴
·红旗软件助力烟草总局 全面建设“数字烟草”
·红旗助力“信访阳光工程”打造畅通信访渠道
·红帽联合FIS发布下一代实时核心银行平台
·红旗助力金盾 打造全无忧出入境信息系统
·红旗Linux全力打造中国邮政总局名址信息库
·爱尔兰证交所从Unix迁移到红帽企业Linux
·一流的意大利银行选择使用红帽企业Linux
·PLUS Finanzservice选择使用红帽企业Linux
·红帽助力TransACT Communications 公司
·法国零售业巨头Lapeyre采用Redhat Linux
·旅游预订网站选择使用红帽企业Linux
·马哈拉施特拉邦政府的红帽解决之道
·美国联邦政府案例
·红帽为慕尼黑展览会提供现代化集群系统
·Yuba郡用开源软件和红帽产品提高了效率
·红帽企业Linux助印度理工建立高性能计算中心
·采用红帽Linux 将系统维护时间缩短了65%
·从UNIX迁移到Linux使Peñoles公司获益非浅
·Hikal公司用红帽企业Linux开展任务关键的ERP项目
·KDE3.5.4新版本发布
·芝加哥商业交易所从Unix向Linux迁移
·南方基金管理有限公司成功案例 Red Hat Linux
·广东北电通讯设备有限公司成功案例
·挪威国家石油公司从UNIX迁移到红帽Linux,成本减半
·中央电视台CCTV动画部案例 Red Hat Linux

  图书

鸟哥的Linux私房菜基础学..


Linux程序设计.第3版


Linux设备驱动开发详解


  下载
·Endian Firewall
·linux kernel(Linux 内核)
·CentOS
·Fedora Core 6
·Scientific Linux
·Slackware 11.0
·Gentoo Linux
·ubuntu-6.10-i386服务器版本
·ubuntu-6.10-amd64服务器版
·ubuntu-6.10-i386桌面版
·ubuntu-6.10-amd64桌面版
·Engarde Linux
您的位置: Linux时代 > 技术文档 > 数据库 >

Sqlite中文排序研究

日期:2006-11-27 作者:absurd 来自:blog.csdn.net


Sqlite是一个用C语言实现的小型SQL数据库引擎。它体积小巧但功能强大,对硬件资源要求很低而且性能表现卓越,非常适合于嵌入式应用环境。最近发现sqlite并不支持中文(拼音/笔画)排序,而这个功能又是我们必需的,所以花了些时间去研究。我对Sqlite的了解只能算是业余级,在研究的过程或许走了些弯路,或许已经有现存的算法可利用,不管怎么样,在研究过程中还是有不少收获,写出来和大家探讨一下。

 

我们知道,计算机中的每一个字符都有一个内码。在默认情况下,计算机排序时,比较两个字符的大小就是比较字符内码的大小,这对于英文来说没有问题,因为英文字母的内码是按字母顺序递增的。对于中文来说,就比较麻烦了:首先,中文的排序方式有多种,比如按内码排序、按拼音排序和按笔画排序,要通过参数指定排序的方式,否则计算机就按内码排序了。其次,汉字的内码顺序即不同于拼音顺序,也不同于按笔画顺序。在GB2312编码中,汉字基本上按拼音排序(据说有例外,不太清楚)。在GBK中,它在GB2312基础上进行了扩充,兼容GB2312中的所有字符,所以不是按拼音排序了。在Unicode中,汉字的排列似乎更没有什么规律可言了。

 

为了解决内码顺序与用户习惯顺序(如拼音顺序)的冲突,在glibclocale数据里,要求提供排序方式(collate)的描述。我看了一下glibc-2.3.5提供的locale数据,在简体中文(zh_CN)locale数据描述里,关于排序方式的描述如下:

% ISO 14651 collation sequence

LC_COLLATE

copy "iso14651_t1"

END LC_COLLATE

 

也就是说,照抄iso14651_t1的排序方式。打开iso14651_t1文件看了一下,也没有发现关于中文的特殊处理,可以推断glibc默认的排序方式就是按unicode排序。

 

所以不能指望glibc提供中文排序功能,如果SQLite支持了中文排序只能是做了特殊处理。浏览了一下SQLite的代码,这种希望似乎也不大。在网上也没有查到相关的资料和补丁,看来只能靠自己了。

 

不过,在浏览SQLite代码时还是有些收获,至少知道了它比较数据记录的过程:

1.         sqlite3VdbeExec调用sqlite3BtreeInsert把记录插入到适当的位置。

2.         sqlite3BtreeInsert调用sqlite3BtreeMoveto找到要插入的位置。

3.         sqlite3BtreeMoveto调用sqlite3VdbeRecordCompare比较两条记录的大小。

4.         sqlite3VdbeRecordCompare调用sqlite3MemCompare比较字段的大小。

5.         sqlite3MemCompare调用binCollFunc去做真正的比较。

6.         binCollFunc是一个回调函数,由外层设置的。

 

进一步研究,知道了binCollFunc的来源:

1.         struct CollSeq是一个用来比较的对象,它带有一个比较函数和相关上下文。

2.         通过multiSelectCollSeq找到合适的CollSeq对象。

3.         multiSelectCollSeq调用sqlite3ExprCollSeq查找。

4.         multiSelectCollSeq调用sqlite3CheckCollSeq查找。

5.         查找标准是SELECTCREATE TABLE所带的COLLATE子句。

6.         也就是说可以通过SELECTCREATE TABLE的参数来决定选择哪个比较函数。

 

基于上面这些认识,我们知道比较函数是可以指定的了。接下来的问题是,我们能否自定义比较函数,如何自定义,以及如何安装到SQLite里。很快发现SQLite已经提供了安装比较函数的接口:

int sqlite3_create_collation16(

  sqlite3* db,

  const char *zName,

  int enc,

  void* pCtx,

  int(*xCompare)(void*,int,const void*,int,const void*)

)

 

int sqlite3_create_collation(

  sqlite3* db,

  const char *zName,

  int enc,

  void* pCtx,

  int(*xCompare)(void*,int,const void*,int,const void*)

)

 

 

前者用来安装UTF-16的比较函数,后者用来安装UTF-8的比较函数。我们发现,在main.c里已经安装了一些内置的比较函数:

sqlite3_create_collation(db, "BINARY", SQLITE_UTF8, 0,binCollFunc);

sqlite3_create_collation(db, "BINARY", SQLITE_UTF16, 0,binCollFunc);

sqlite3_create_collation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc);

 

好了,原理清楚了,我们要做的只是提供一个比较函数,并且安装进去就OK了。为了测试,我写一个按拼音排序的比较函数(按笔画排序类似):

int pinyin_cmp(

    void *NotUsed,

    int nKey1, const void *pKey1,

    int nKey2, const void *pKey2)

{

    int n = nKey1 < nKey1 ? nKey1 : nKey2;

 

    return pinyin_strncmp(pKey1, pKey2, n + 1);

}

 

 

安装比较函数时要注意,因为我们实现的比较函数是针对UTF-16的,所以名字要用UTF-16编码。但是由于linux下默认的wchar_t32位的,不能直接用L”pinyin”的方式把ANSI字符串转换成UTF-16字符串,只能按下列方式。

unsigned short zName[] = {'p', 'i', 'n', 'y', 'i', 'n', 0};

sqlite3_create_collation16(db, zName, SQLITE_UTF16, 16, pinyin_cmp);

 

测试结果正常(红色部分为按拼音排序,蓝色部分为默认排序):

sqlite> create table person(name text, age int);

sqlite> insert into person values("张三", 23);

sqlite> insert into person values("张三丰", 23);

sqlite> insert into person values("李四", 24);

sqlite> insert into person values("李四叔", 24);

sqlite> insert into person values("王五", 25);

sqlite> insert into person values("王五妹", 25);

sqlite> insert into person values("赵七", 26);

sqlite> insert into person values("赵七姑", 26);

sqlite>

sqlite> select * from person order by name collate pinyin;

李四|24

李四叔|24

王五|25

王五妹|25

张三|23

张三丰|23

赵七|26

赵七姑|26

sqlite> select * from person order by name;              

张三|23

张三丰|23

李四|24

李四叔|24

王五|25

王五妹|25

赵七|26

赵七姑|26

 

总结:SQLite的架构设计非常优秀,接口定义得也比较合理,支持中文排序变得非常简单。

原文链接:http://blog.csdn.net/absurd

本文被浏览



 相关新闻

ucLinux下sqlite数据库移植全攻略2006-11-27 16:01:37
MySQL 企业级支持服务全新推出2006-11-22 11:14:32
MySQL欲建世界最大数据仓库2006-11-15 09:29:08
MySQL想做成为数据库界的Google?2006-11-13 11:13:05
MySQL:昨天的"玩具"到今天的竞争者2006-11-10 09:48:48
MySQL的一些安全注意点2006-11-08 15:17:14
PostgreSQL介绍及安装指南2006-11-03 15:43:49
在MySQL 数据库中使用C 执行SQL语句2006-10-24 15:25:58
Linux下免费数据库PostgreSQL开发入门2006-10-24 15:11:25


 相关评论
关于我们 | 联系方式 | 广告合作 | 诚聘英才 | 网站地图 | 免费注册

Copyright © 2001-2006 ChinaUnix.net All Rights Reserved

感谢所有关心和支持过ChinaUnix的朋友们

京ICP证041476号