中文按拼音首字母排序的C++实现方案
先介紹下背景,最近有個需求,需要將用戶的好友列表按照昵稱的拼音首字母排序,類似于手機電話簿的聯系人。一開始建議讓終端同學去做這點,畢竟終端現有的電話簿模塊已經實現了,不過終端同學說電話簿是系統組件,移植出來需要額外開發,導入庫等等。建議后臺來實現,終端直接接受處理好的數據,于是就由后臺來做了。對于這個問題剛開始沒有什么思路,不知道怎么著手,問題包括如何識別昵稱里的中文、中文如何轉換為拼音等等。咨詢了組內的大佬,給出建議:首先,中文字符是可以識別出來的,因為我們編碼都是統一的utf8編碼,utf8是unicode編碼的一種實現方式,在unicode編碼標準中,中文字符的unicode編碼范圍是0X4E00~0X9FA5,可以通過檢測這一范圍來識別中文,這樣,第一個問題解決了。其次,中文轉拼音,預先準備好一個字典map,存儲中文和拼音的對應關系,轉換的時候直接讀取map。這里中文拼音對應關系其實已有前輩做過,github上有了映射文件,可以直接拿來使用。
兩個難題解決了,方案就出來了,分為三部分:首先是拼音map的生成處理,其次是中文的識別以及轉換,最后是業務處理。demo的效果圖如下:
圖1. github上的中文拼音字典格式,鏈接放在參考文檔里
圖2. 編譯運行截圖?
參考代碼:
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) {// 路徑校驗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,數字表示聲調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){// 發音有多個,我們只取一個zh.assign(tmp_pinyin, 0, i);pinyin.assign(tmp_pinyin, i+1, tmp_pinyin.size()-i-1);// 去掉拼音末尾聲調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;}}}// 關閉文件is.close();return 0; }2. 中文轉換部分:
/* Convert.h */#include <map> #include <string>using namespace std; class Convert { public:Convert(){}~Convert(){}public:// 昵稱轉換中文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);// 中文占用三字節,utf8中三字節編碼第一個字節前四位是1110if((*p & 0xF0) == 0xE0 && IsZh(p)){ tmp_str.append(&nickname.at(i), 3); // 從字典里找對應的拼音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個字節,下面是分別對三個字節校驗,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. 主函數
#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;// 拼音轉換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 關系
3. github 拼音鏈接
?
================================================================================================
Linux應用程序、內核、驅動、后臺開發交流討論群(745510310),感興趣的同學可以加群討論、交流、資料查找等,前進的道路上,你不是一個人奧^_^。...
總結
以上是生活随笔為你收集整理的中文按拼音首字母排序的C++实现方案的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql 慢查询 定位过程,和orde
- 下一篇: 联想电脑怎么一键安装 联想电脑如何一键安