Sqlite中文排序研究
转载时请注明出处和作者联系方式:http://blog.csdn.net/absurd
作者联系方式:Li XianJing <xianjimli at hotmail dot com>
更新时间:2006-12-19
Sqlite是一个用C语言实现的小型SQL数据库引擎。它体积小巧但功能强大,对硬件资源要求很低而且性能表现卓越,非常适合于嵌入式应用环境。最近发现sqlite并不支持中文(拼音/笔画)排序,而这个功能又是我们必需的,所以花了些时间去研究。我对Sqlite的了解只能算是业余级,在研究的过程或许走了些弯路,或许已经有现存的算法可利用,不管怎么样,在研究过程中还是有不少收获,写出来和大家探讨一下。
我们知道,计算机中的每一个字符都有一个内码。在默认情况下,计算机排序时,比较两个字符的大小就是比较字符内码的大小,这对于英文来说没有问题,因为英文字母的内码是按字母顺序递增的。对于中文来说,就比较麻烦了:首先,中文的排序方式有多种,比如按内码排序、按拼音排序和按笔画排序,要通过参数指定排序的方式,否则计算机就按内码排序了。其次,汉字的内码顺序即不同于拼音顺序,也不同于按笔画顺序。在GB2312编码中,汉字基本上按拼音排序(据说有例外,不太清楚)。在GBK中,它在GB2312基础上进行了扩充,兼容GB2312中的所有字符,所以不是按拼音排序了。在Unicode中,汉字的排列似乎更没有什么规律可言了。
为了解决内码顺序与用户习惯顺序(如拼音顺序)的冲突,在glibc的locale数据里,要求提供排序方式(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. 查找标准是SELECT或CREATE TABLE所带的COLLATE子句。
6. 也就是说可以通过SELECT或CREATE 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_t是32位的,不能直接用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的架构设计非常优秀,接口定义得也比较合理,支持中文排序变得非常简单。
(关于pinyin_strncmp的实现,将在下一篇文章中介绍)
~~end~~
分享到:
相关推荐
一种非常简单的方式解决Sqlite中文排序问题(网页)
sqlite汉字拼音对照表,有 常用汉字表6986个 和 gbk汉字库21000个 两张表,带汉字的gbk编码
易语言模块Sqlite表管理.rar 易语言模块Sqlite表管理.rar 易语言模块Sqlite表管理.rar 易语言模块Sqlite表管理.rar 易语言模块Sqlite表管理.rar 易语言模块Sqlite表管理.rar
基于Android平台的SQLite数据库加密研究.pdf
《SQLite 中文教程》有助于初学者了解 SQLite 数据库引擎相关的基础知识和先进理念。主要介绍了本教程提供了所有重要的内置的 SQLite 函数的参考手册,同时也列出了SQLite 数据库网站和书籍。 本教程帮助您了解什么...
sqlite3 for delphi 自己修改的版本 解决中文乱码问题
换点积分好下载点儿东西,谢谢大家!是从mdb 转过来的。东西不错,比较全。大家一起用用吧!
sqlite_column —— 在当前的行中取得一列(a column from the current row of a result set)。 sqlite_create_aggregate —— Register an aggregating UDF for use in SQL statements。 sqlite_create_function ...
sqlite(中文API) sqlite(中文API) sqlite(中文API) sqlite(中文API) sqlite(中文API)
基于wal预写日志的SQLite恢复技术研究与应用 毕业设计论文
在Java下连接SQLite数据库 一、下载SQLite数据库的JDBC:http://www.zentus.com/sqlitejdbc/ 二、将下载到的包解压后得到jar包放到%JAVA_HOME%\lib下,并且将其添加到ClassPath系统环境变量中。一定要保证在类路径...
SQLite.Interop.dll for sqlite expert ...2.重新打开SQLite Expert,Tools --> Options --> Data --> SQLite Library中选择“SQLite.Interop.dll *****”那一项,点击 OK; 3.不好使,就重启下sqlite expert
一些小型的应用程序需要使用到数据库,sqlite可以说是最好的选择。这里个人整理了一般简单通用的操作类SQLiteHelper
sqlite 支持中文模糊查询 sqlite3的许多版本不支支持 like 查询,此版版本支持,难得。
SQLite 安装包 sqlite3 及sqlite数据库jdbc jar包 2分不能再少了
SQLite在嵌入式Web服务器中的应用研究
该项目为unicode编码格式,一个简单的操作sqlite的Demo,支持简单的增删查改,支持中文路径,中文文件名,中文表名,中文列名,中文内容。可以在此基础上添加自己想要的各种操作 项目中用到的sqlite3.dll,sqlite3....
SQLite中文文档 SQLite中文文档 SQLite中文文档 SQLite中文文档 SQLite中文文档 SQLite中文文档
sqlite数据库存取中文乱码的全部解决方案(包括其它数据库oracle+sqlserver+mysql) 数据库的连接方式、数据库里存放数据的字体编码、所选编程语言的缺省字体编码。如果在编程中遇到不能正确显示中文时、、、、
SQLITE数据库查询时中文乱码;