中文名字排序

因?yàn)轫?xiàng)目需要對一些中文名字的物品進(jìn)行排序,我在C#控制臺工程下面測試,直接使用系統(tǒng)的List.Sort()函數(shù)是可以自動(dòng)進(jìn)行排序的。但是把同樣的代碼拷貝到Unity中排序就是錯(cuò)亂的了。

經(jīng)過一番Google之后,最終猜測應(yīng)該是下面這個(gè)原因。

對于C#控制臺工程代碼,系統(tǒng)采用的字符集應(yīng)該是GB2312或者GBK,我在網(wǎng)上找了一個(gè)GB2312的字符集對應(yīng)表http://ash.jp/code/cn/gb2312tbl.htm?發(fā)現(xiàn)漢字的編碼是按照拼音的先后順序排序的。而Unicode的字符集中的漢字是按照筆畫和偏旁部首來進(jìn)行排序的。

完整的Unicode中文字符集部分下載地址:

https://download.csdn.net/download/hongkenzhao/12883276

所以猜測,Unity中之所以用List.Sort()來進(jìn)行排序中文名字出現(xiàn)錯(cuò)亂的問題,主要是因?yàn)閁nity采用了Unicode字符集導(dǎo)致的。下圖是Unity中字體選擇字符集的選項(xiàng)。

解決方案一

思路:把Unicode字符集中的漢字的碼值轉(zhuǎn)換成GB2312或者GBK的碼值,然后再對碼值進(jìn)行排序。

網(wǎng)上有解決方案是通過把Unicode的碼值和GBK的碼值通過一個(gè)數(shù)組建立起來索引關(guān)系

文件的下載可以在Google里面搜索FatFs關(guān)鍵字,然后選擇“FatFs - Generic FAT Filesystem Module”中的Previous

Release進(jìn)行下載。如果下載是失敗可以通過這個(gè)鏈接進(jìn)行下載:https://download.csdn.net/download/hongkenzhao/12888729


Unicode和GBK兩個(gè)碼值的轉(zhuǎn)換cc936.c文件內(nèi)有C語言實(shí)現(xiàn)的函數(shù)

這是C#語言版本的實(shí)現(xiàn)

???????public static UInt32 Convert2GBK(UInt32uni_)

???????{

??????????? inti, n, li, hi;


??????????? UInt32gbk = 0;

??????????? if (uni_< 0x80)

??????????? {

??????????????? gbk = uni_;

??????????? }

??????????? else

??????????? {

??????????????? hi = uni2oem.Length/ 2 - 1;


??????????????? i= 0;

??????????????? li= 0;

??????????????? for (n = 16; n != 0; n--)

??????????????? {

??????????????????? i = li + (hi - li) / 2;

??????????????????? if (uni_ == uni2oem[i* 2])

??????????????????????? break;

??????????????????? if (uni_ > uni2oem[i* 2])

??????????????????? {

??????????????????????? li = i;

??????????????????? }

??????????????????? else

??????????????????? {

??????????????????????? hi = i;

??????????????????? }

??????????????? }

??????????????? gbk = n != 0 ? uni2oem[i* 2 + 1] : 0;

??????????? }


??????????? return gbk;

???????}

現(xiàn)在有了碼值了,怎么進(jìn)行排序。我當(dāng)時(shí)是根據(jù)轉(zhuǎn)換的到的GBK的碼值,拼接成一個(gè)數(shù)字字符串,然后根據(jù)字符串進(jìn)行排序。這個(gè)方案是有問題的,在數(shù)字、字母和漢字混排的時(shí)候。最終選擇放棄了這個(gè)方案,選擇了方案二。

Unicode和GBK轉(zhuǎn)換的參考鏈接:

https://blog.csdn.net/yanchao7788/article/details/53196901

方案二

思路:把漢字轉(zhuǎn)換成拼音,然后按照拼音的字母順序進(jìn)行排序

把漢字轉(zhuǎn)換成拼音網(wǎng)上有兩種方案:第一種是微軟官方的庫文件Microsoft Visual Studio International Pac里面有一個(gè)簡體中文拼音轉(zhuǎn)換的庫Simplified Chinese?Pin-Yin Conversion

Library支持把中文轉(zhuǎn)換成拼音或拼音首字母縮寫。這個(gè)類庫有個(gè)缺點(diǎn),就是遇到多音字的時(shí)候只會按照字母排序排序取出第一個(gè)拼音作為這個(gè)字的拼音,比如“石”(shi、dan)是多音字,它會顯示為dan,還有“廣”(guan、an),它會顯示為an,這就是網(wǎng)上好多人說微軟的庫不準(zhǔn),常用字轉(zhuǎn)換拼音都轉(zhuǎn)換錯(cuò)誤,其實(shí)不是轉(zhuǎn)換錯(cuò)誤而是你的小學(xué)語文是體育老師教的,遇到多音字就不認(rèn)識它了。具體怎么使用微軟這個(gè)庫可以參考下面這篇blog,里面有詳細(xì)的使用說明:https://blog.csdn.net/zhupengfei/article/details/107662581

第二種方案是谷歌的NPinyin開源庫文件,這個(gè)是有源碼的,源碼地址:https://code.google.com/archive/p/npinyin/這個(gè)庫在github上面也有個(gè)比人的鏈接可以下載到源碼:https://github.com/2881099/NPinyin

NPinyin這個(gè)庫解決了多音字選擇問題,通過源碼可以看出它是通過建立拼音和漢字之間的索引關(guān)系來實(shí)現(xiàn)的。這樣就可以把常用字按照常用的拼音進(jìn)行匹配,手動(dòng)的填充了。但是這個(gè)字庫也有缺陷,里面的字太少,一些生僻字或者常用的繁體字是無法找到的。如果想手動(dòng)擴(kuò)充也可以,后面會介紹一下NPinyin的實(shí)現(xiàn)原理。但是問題是我們不知道要擴(kuò)充多少個(gè)字呀,所有解決方案是優(yōu)先使用NPinyin庫查找字的拼音,如果查找失敗,那么再去微軟的PinyinConversion庫中找拼音,這樣就可以找到正確的拼音了。

NPinyin庫的實(shí)現(xiàn)原理是通過PyCode.cs來定義拼音對應(yīng)的漢字一維數(shù)組。然后通過漢字的對應(yīng)的Unicode的碼值和漢字?jǐn)?shù)組長度取模,算出一個(gè)數(shù)字記做hash值,然后放到PyHash.cs文件內(nèi)的二維hash數(shù)組中。當(dāng)做一維的索引,那么二維的索引值是怎么來的,它是通過查找PyCode的拼音所在的索引來確定的。舉個(gè)例子:阿->0x963f(十六進(jìn)制碼值)-> 38463(十進(jìn)制)-> 38463%399(399是PyCode漢字?jǐn)?shù)組長度)->159(就對應(yīng)PyHash中一維的所有,二維的索引就阿的拼音“a”所在的索引0)->[159]{0}這個(gè)就是最終的轉(zhuǎn)換結(jié)果。

有了正確的拼音該怎么排序,下面簡單介紹一下排序規(guī)則,把漢字(或者數(shù)字,字母、漢字混合都可以)轉(zhuǎn)換成拼音數(shù)組和漢字單個(gè)字符數(shù)組,然后先比較拼音數(shù)組,如果拼音數(shù)字相同,那么就比較漢字的Unicode碼值,如果碼值也相等,就之間比較漢字的字符長度,字符短的排在前面就可以了。通過這個(gè)排序規(guī)則就可以把漢字進(jìn)行正確的排序了。下面是排序規(guī)則的排序函數(shù)代碼:

public class NameStruct : IComparable<NameStruct>

{

???public string strChinese = default;

???public List<char> chineseList = default;

???public List<string> pinyinList = default;


???public NameStruct() { }

???public NameStruct(string chinese_, List<char> chList_, List<string> pyList_)

???{

???????strChinese = chinese_;

???????chineseList = chList_;

???????pinyinList = pyList_;

???}


???//Sort by Chinese Pinyin And Unicode Code

Value

???int IComparable<NameStruct>.CompareTo(NameStructother)

???{

???????int size1 =Mathf.Min(this.chineseList.Count, other.chineseList.Count);

???????int size2 =Mathf.Min(this.pinyinList.Count, other.pinyinList.Count);


???????for (int i = 0; i < size1; i++)

???????{

??????????? if (this.pinyinList[i].CompareTo(other.pinyinList[i]) == 0)

??????????? {

??????????????? if (i == size1- 1)

??????????????? {

??????????????????? for (int j = 0; j < size2; ++j)

??????????????????? {

??????????????????????? if (this.chineseList[j].CompareTo(other.chineseList[j]) != 0)

??????????????????????? {

??????????????????????????? return this.chineseList[j].CompareTo(other.chineseList[j]);

??????????????????????? }

??????????????????? }

??????????????? }

??????????? }

??????????? else

??????????? {

??????????????? return this.pinyinList[i].CompareTo(other.pinyinList[i]);

??????????? }

???????}


???????if (this.chineseList.Count > other.chineseList.Count)

???????{

??????????? return1;

???????}

???????else

???????{

??????????? return-1;

???????}

???}

}

完整的項(xiàng)目測試代碼下載地址:

https://download.csdn.net/download/hongkenzhao/12895744


備注:下面是我在測試過程中用到的碼值查詢網(wǎng)站,貼出來方便大家使用。

GBK碼值查詢地址:

http://www.mytju.com/classCode/tools/encode_gb2312.asp

Unicode碼值查詢地址:

https://tool.chinaz.com/tools/unicode.aspx

ASCII碼的碼值查詢地址:

https://tool.oschina.net/commons?type=4

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容