中文按拼音首字母排序的C++实现方案
先介紹下背景,最近有個需求,需要將用戶的好友列表按照昵稱的拼音首字母排序,類似于手機(jī)電話簿的聯(lián)系人。一開始建議讓終端同學(xué)去做這點(diǎn),畢竟終端現(xiàn)有的電話簿模塊已經(jīng)實(shí)現(xiàn)了,不過終端同學(xué)說電話簿是系統(tǒng)組件,移植出來需要額外開發(fā),導(dǎo)入庫等等。建議后臺來實(shí)現(xiàn),終端直接接受處理好的數(shù)據(jù),于是就由后臺來做了。對于這個問題剛開始沒有什么思路,不知道怎么著手,問題包括如何識別昵稱里的中文、中文如何轉(zhuǎn)換為拼音等等。咨詢了組內(nèi)的大佬,給出建議:首先,中文字符是可以識別出來的,因?yàn)槲覀兙幋a都是統(tǒng)一的utf8編碼,utf8是unicode編碼的一種實(shí)現(xiàn)方式,在unicode編碼標(biāo)準(zhǔn)中,中文字符的unicode編碼范圍是0X4E00~0X9FA5,可以通過檢測這一范圍來識別中文,這樣,第一個問題解決了。其次,中文轉(zhuǎn)拼音,預(yù)先準(zhǔn)備好一個字典map,存儲中文和拼音的對應(yīng)關(guān)系,轉(zhuǎn)換的時候直接讀取map。這里中文拼音對應(yīng)關(guān)系其實(shí)已有前輩做過,github上有了映射文件,可以直接拿來使用。
兩個難題解決了,方案就出來了,分為三部分:首先是拼音map的生成處理,其次是中文的識別以及轉(zhuǎn)換,最后是業(yè)務(wù)處理。demo的效果圖如下:
圖1. github上的中文拼音字典格式,鏈接放在參考文檔里
圖2. 編譯運(yùn)行截圖?
參考代碼:
1. 字典解析部分
/* PinyinMapParser.h */#include <map> #include <string>using namespace std; class PinyinMapParser { public:PinyinMapParser(){}~PinyinMapParser(){}public:// 從文件中獲取拼音字典static int GetPinYinMap(string& path, map<string, string>& pin_yin_map); };/* PinyinMapParser.cpp */#include <iostream> #include <fstream> #include "PinyinMapParser.h"// 獲取拼音映射文件 int PinyinMapParser::GetPinYinMap(string& path, map<string, string>& pin_yin_map) {// 路徑校驗(yàn)if (path.empty()){cout<<"path emtpy, invalid param"<<endl;return -1;}// 讀取拼音文件std::ifstream is(path.c_str());if (!is.is_open()){cout<<"open file:"<<path<<" error"<<endl;return -1;}while (!is.eof()){string tmp_pinyin;// 每次讀取一行,這里拼音文件格式:王=wang1,wang2,數(shù)字表示聲調(diào)getline(is, tmp_pinyin);//cout<<"getline:"<<tmp_pinyin<<endl;if (tmp_pinyin.find("=") != string::npos){string zh, pinyin;size_t i = tmp_pinyin.find_first_of('=');if (i != string::npos && i != tmp_pinyin.size()-1){// 發(fā)音有多個,我們只取一個zh.assign(tmp_pinyin, 0, i);pinyin.assign(tmp_pinyin, i+1, tmp_pinyin.size()-i-1);// 去掉拼音末尾聲調(diào)if (pinyin.find(",") != string::npos){size_t j = pinyin.find(","); pinyin.assign(pinyin, 0, j-1);}else{pinyin.assign(pinyin.begin(), pinyin.end()-1);}// 取出來后放到字典里//cout<<"zh:"<<zh<<", pinyin:"<<pinyin<<endl;pin_yin_map[zh] = pinyin;}}}// 關(guān)閉文件is.close();return 0; }2. 中文轉(zhuǎn)換部分:
/* Convert.h */#include <map> #include <string>using namespace std; class Convert { public:Convert(){}~Convert(){}public:// 昵稱轉(zhuǎn)換中文static int ConvertNicknameToPinyin(string& nickname, string& convert_str, map<string, string>& pinyin_map);// 判斷是否是中文static bool IsZh(const char* p); };/* Convert.cpp */#include <iostream> #include <string> #include "Convert.h"// 獲取拼音映射文件 int Convert::ConvertNicknameToPinyin(string& nickname, string& convert_str, map<string, string>& pinyin_map) {// 檢查昵稱是否為空if (nickname.empty()){cout<<"nickname is empty, invalid"<<endl;return -1;}{size_t i = 0; string tmp_str;// 逐個字符檢查while(i < nickname.length()){try {tmp_str.clear();const char *p = &nickname.at(i);// 中文占用三字節(jié),utf8中三字節(jié)編碼第一個字節(jié)前四位是1110if((*p & 0xF0) == 0xE0 && IsZh(p)){ tmp_str.append(&nickname.at(i), 3); // 從字典里找對應(yīng)的拼音if (pinyin_map.find(tmp_str) != pinyin_map.end()){convert_str.append(pinyin_map[tmp_str]);}else{cout<<"can't find zh pinyin,zh:"<<tmp_str<<endl;convert_str.append(tmp_str);}i += 3;}else{convert_str.append(p,1);i += 1;}}catch (...){cout<<"exception occurs"<<endl;return -1;}} }return 0; }// 判斷是否是中文 bool Convert::IsZh(const char* p) {if ( NULL == p){cout<<"input param null"<<endl;return false;}// 中文unicode編碼范圍是0X4E00~0X9FA5,即utf8范圍0xe4b880 ~ 0xe9baa5// 使用utf8編碼占3個字節(jié),下面是分別對三個字節(jié)校驗(yàn),utf8編碼介紹 https://blog.csdn.net/zhusongziye/article/details/84261211if ((*p&0xF0) == 0xE0){if( *(p+1) == '\0' || *(p+2) == '\0'){return false;}unsigned char v = *p;unsigned char v1 = *(p+1);unsigned char v2 = *(p+2);if( (v1&0xC0) != 0x80 || (v2&0xC0) != 0x80 ){return false;}if( v < 0xE4){return false;}if( v == 0xE4 && v1 < 0xB8){return false;}if( v == 0xE4 && v1 == 0xB8 && v2 < 0x80){return false;}if(v > 0xE9){return false;}if(v == 0xE9 && v1 > 0xBE){return false;}if(v == 0xE9 && v1 == 0xBE && v2 > 0xB5){return false;}p += 3;return true;}return false; }3. 主函數(shù)
#include <iostream> #include <map> #include <string> #include "PinyinMapParser.h" #include "Convert.h"using namespace std;int main (int argc, char** argv) {int ret = 0;if (argc < 3){cout<<"Usage: ./exe file_path"<<endl;return -1;}string path(argv[1]);//cout<<"input param:"<<path<<endl;map<string, string> m_pinyin;// 解析拼音字典ret = PinyinMapParser::GetPinYinMap(path, m_pinyin);if (ret != 0){cout<<"GetPinYinMap error, ret:"<<ret<<", path:"<<path<<endl;return ret;}string zh(argv[2]);string zhpinyin;// 拼音轉(zhuǎn)換ret = Convert::ConvertNicknameToPinyin(zh, zhpinyin, m_pinyin);if (ret != 0){cout<<"parse "<<zh<<" error"<<endl;return ret;}cout<<"parse succ, zh:"<<zh<<", pinyin:"<<zhpinyin<<endl;return ret; }?
參考資料:
1.?漢字 Unicode 編碼范圍
2.?Unicode 和 UTF-8 關(guān)系
3. github 拼音鏈接
?
================================================================================================
Linux應(yīng)用程序、內(nèi)核、驅(qū)動、后臺開發(fā)交流討論群(745510310),感興趣的同學(xué)可以加群討論、交流、資料查找等,前進(jìn)的道路上,你不是一個人奧^_^。...
總結(jié)
以上是生活随笔為你收集整理的中文按拼音首字母排序的C++实现方案的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql 慢查询 定位过程,和orde
- 下一篇: c++大作业迷宫游戏 规定时间内完成_开