Sqlite   发布时间:2022-05-22  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了Sqlite中文排序研究大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

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*,const void*)

)

int sqlite3_create_collation(

sqlite3* db,const void*)

)


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

sqlite3_create_collation(db,"BINARY",@R_342_5607@UTF8,binCollFunc);

sqlite3_create_collation(db,@R_342_5607@UTF16,"NOCASE",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'',0};

sqlite3_create_collation16(db,zname,16,pinyin_cmp);

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

sqlite> create table person(@R_93_4687@t,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://www.diybl.com/course/3_program/c++/cppjs/2008324/106096.html

大佬总结

以上是大佬教程为你收集整理的Sqlite中文排序研究全部内容,希望文章能够帮你解决Sqlite中文排序研究所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。