c语言中文拼音排序,为sqlite增加汉字拼音排序功能

此文已由作者严跃杰授权网易云社区发布。

欢迎访问网易云社区,了解更多网易技术产品运营经验。

Sqlite3是一款C语言实现的小型SQL数据库引擎,它体积小巧但功能强大, 性能表现也非常不错, 因此在客户端及嵌入式应用开发中受到广泛的欢迎。在网易云音乐的开发中,我们就用到了sqlite3,但是不幸的是在开发过程中发现它不支持汉字拼音排序,但这又是必须的功能。今天我们就来看下如何为sqlite3添加汉字拼音排序的功能。

首先我们想到的是既然原生不支持拼音排序,那它是否提供了扩展接口允许我们添加自定义排序功能呢?通过网上查找和文档阅读,果不其然,它为提供了安装比较函数的接口:

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的比较函数。

除了扩展接口,还有一项资源是必须要有的,当然就是汉字拼音库。网上一通猛找,发现没有合适的。后来发现是云音乐资源包里已经有一个现成的汉字拼音库,省却了不少麻烦(共享在附件工程解决方案目录下)。

必要的资源有了,就可以着手实现了。

以下是获取汉字拼音实现

std::wstring LetterHelp::ConvertLetterToPinyin(const std::wstring& chinese)

{

std::wstring str_pinyin;for(unsigned int i = 0; i 

{wchar_t tch = chinese[i];const char *pinyin_char = GetLetter((unsigned short)tch);

if(pinyin_char)

{int len = strlen(pinyin_char);

wchar_t* wch = new wchar_t[len];

FUTF82WConvert(pinyin_char,wch, len);

str_pinyin.append(wch);

}else

{

str_pinyin.push_back(tch);

}

}return str_pinyin;

}const char* LetterHelp::GetLetter(unsigned short ch)

{if(ch >= HANZI_MIN && ch <= HANZI_MAX)return m_pinyin + m_code[ch - HANZI_MIN];else

return nullptr;

}

以下比较函数实现:

// 两个都是汉字时比较函数static int pinyin_strcmp(const wchar_t *key1, const wchar_t *key2) {

std::wstring str1 = LetterHelp::getInstance()->ConvertLetterToPinyin(key1);

std::wstring str2 = LetterHelp::getInstance()->ConvertLetterToPinyin(key2);return wcscmp(str1.c_str(), str2.c_str());

}// 升序排序时将数字,字母排到汉字前static int pinyin_cmplmpl(int nKey1, const void *pKey1,int nKey2, const void *pKey2) {int size = min(nKey1, nKey2);int i = 0, flag = 0, ret = 0;;wchar_t s[2]={0}, d[2]={0};for (i = 0; i 

flag = 0;

ret = 0;

s[0] = *((wchar_t*)pKey1+i);

d[0] = *((wchar_t*)pKey2+i);

if ((int)s[0] > HANZI_MAX || (int)s[0] 

flag += 1;

} else {

flag += 2;

}

if ((int)d[0] > HANZI_MAX || (int)d[0] 

flag += 4;

} else {

flag += 8;

}switch(flag) {

case  5:

ret = wcscmp(s, d);

if (ret != 0) {

return ret;

}

break;

case 9:

return -1;

case 6:

return 1;

case 10:

ret = pinyin_strcmp(s, d);

if (ret != 0) {

return ret;

}

break;

}

}if (i >= size && nKey1 == nKey2) {

return 0;

} else if (i >= size && nKey1 

return -1;

} else if(i >= size && nKey1 > nKey2) {

return 1;

}return -1;

}// 升序比较函数static int pinyin_cmp_asc(

void *NotUsed,int nKey1, const void *pKey1,

int nKey2, const void *pKey2)

{return pinyin_cmplmpl(nKey1,pKey1,nKey2,pKey2);

}// 降序比较函数static int pinyin_cmp_desc(

void *NotUsed,int nKey1, const void *pKey1,

int nKey2, const void *pKey2)

{int ret = pinyin_cmplmpl(nKey1,pKey1,nKey2,pKey2);

if (ret == 0) {

return ret;

} else {

return -ret;

}

}

在打开数据库后安装汉字拼音比较函数

// 打开数据库文件并安装汉字拼音比较函数bool Db::open(const string path) {

if (db != nullptr) {

cout <

return false;

}int ret = sqlite3_open(path.c_str(), &db);

if(ret != SQLITE_OK){

cout <

return false;

}unsigned short asc[] = {'p', 'i', 'n', 'y', 'i', 'n', '_', 'a', 's', 'c', 0};

sqlite3_create_collation16(db, asc, SQLITE_UTF16, 0, pinyin_cmp_asc);

unsigned short desc[] = {'p', 'i', 'n', 'y', 'i', 'n', '_', 'd', 'e', 's', 'c', 0};

sqlite3_create_collation16(db, desc, SQLITE_UTF16, 0, pinyin_cmp_desc);return true;

}

最后如下sql进行测试

select * from person order by name collate pinyin_asc

select * from person order by name collate pinyin_desc

测试结果如下

5cd626c936454d5d2a50577c3a151de6.png

5a22a4e343e6c58356baee7dc7861943.png

1d9c50d4743558999f0fc2c1c5b559a8.png

网易云免费体验馆,0成本体验20+款云产品!

更多网易技术、产品、运营经验分享请点击。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值