今天和大家分享一個從Android系統(tǒng)源代碼提取出來的漢字轉成拼音實現(xiàn)方案磷杏,只要一個類溜畅,560多行代碼就可以讓你輕松實現(xiàn)漢字轉成拼音的功能,且無需其他任何第三方依賴极祸。
需求場景
實際開發(fā)過程中需要用到實現(xiàn)漢字轉成拼音的場景比較常見慈格,如:通訊錄里的聯(lián)系人字母導航欄,為沒有設置頭像的用戶生成一個名字首字母的頭像遥金,國家(省份浴捆、城市)字母導航欄,搜索關鍵字轉換成拼音等稿械。
實現(xiàn)方案
Android平臺上將漢字轉換成為拼音已經有一些開源的第三方實現(xiàn)方案选泻,如pinyin4j和TinyPinyin
pinyin4j:https://sourceforge.net/projects/pinyin4j
TinyPinyin:https://github.com/promeG/TinyPinyin
以上這兩個實現(xiàn)方案,都需要引入不少類以及一些相應的編碼文件美莫,這里和大家介紹一個比上面兩個方案還要精簡的實現(xiàn)方案页眯,只要560行代碼且無需依賴于其他任何編文件的實現(xiàn)。這個類是從Android系統(tǒng)通訊錄源碼中提取的厢呵,類名為HanziToPinyin窝撵,其類文件路徑如下:
/packages/providers/ContactsProvider/src/com/android/providers
/contacts/HanziToPinyin.java
這是一個很獨立的類,需要使用的項目直接拷貝到自己對應的工程里面即可使用述吸,需要注意的是忿族,我是在Android 4.2.2的系統(tǒng)源碼中拷貝出來的锣笨,為什么選擇4.2.2,一個是4.2.2之后(4.3開始)的HanziToPinyin不再可以獨立使用道批,需要依賴于Transliterator错英,而這個類我們是無法直接引用的。
而Android 2.x的HanziToPinyin在測試了很多轉換的結果發(fā)現(xiàn)是錯誤的隆豹,所以選擇了最后一個可以采納使用的版本Android 4.2.2椭岩。
如何使用
HanziToPinyin這個類的代碼量非常少,結構也非常簡單
下面簡單的說明一下如何使用璃赡,非常簡單判哥,只需要把需要轉換的漢字傳入get方法即可獲取返回的拼音結果
其返回的數據結構是一個HanziToPinyin.Token的ArrayList,HanziToPinyin.Token是HanziToPinyin中的一個公共靜態(tài)外部類碉考,
其分別有type塌计、source、target等三個成員變量侯谁,type是標識token的類型锌仅,有三種不同的取值1(拉丁文),2(拼音)墙贱,3(未知)热芹,source是輸入的中文,target則是中文轉換后對應的拼音惨撇。這里還有一個細節(jié)需要注意一下伊脓,只拷貝HanziToPinyin在原生系統(tǒng)上使用是沒有問題的,但是在國產手機的ROM上則無法正常使用魁衙,需要加上下面三行代碼做適配:
否則HanziToPinyin的初始化狀態(tài)會設置錯誤报腔,而導致無法實現(xiàn)漢字轉換成拼音。
內部實現(xiàn)
了解完如何使用后纺棺,我們來簡單窺探一下HanziToPinyin內部是如何實現(xiàn)的榄笙,先來看一下類中比較耀眼的兩個數組UNIHANS和PINYINS(兩個類很長,截圖沒截全祷蝌,大家自己看代碼吧)
其中UNIHANS是一組漢字對應的unicode編碼茅撞,而PINYINS則是UNIHANS中每個元素對應的拼音的ASCII碼,如UNIHANS的第一個元素是\u963f巨朦,其對于的中文是阿米丘,換成拼音則是A,而A對應的ASCII碼用十進制表示則是65糊啡,對應的就是PINYINS的第一個數組中的第一個元素拄查,至于為什么后面有5個0的元素,主要是因為漢字的拼音最長的有六個字母(例如:chuang)棚蓄,而阿只有一個a堕扶,所以后面的5個空位就需要用0來填充了碍脏。我們在調用get方法時將中文以String的形式傳入,方法內部會遍歷String中的每個元素稍算,為其生成對應的Token典尾,也就是我們最后拿到的那個ArrayList中的結果。
所以最關鍵的實現(xiàn)是在getToken方法中糊探,這里忽略getToken前面的30來行判斷代碼钾埂,直接看關鍵部分
通過二分檢索的方式,使用java.text.Collator的compare方法不斷比對UNIHANS數組中與輸入的漢字同音(注意:這里是同音不是完全相同)的字科平,最終獲取其對應的在UNIHANS數組中的下標位置offset褥紫。前面我們提到UNIHANS和PINYINS是相互對應的,所以這里也能找到PINYINS中對應讀音的一組ASCII碼瞪慧,通過int轉換成char髓考,再使用StringBuilder進行拼接,就可以獲取對應的拼音了汞贸,實現(xiàn)思路上還是很簡單清晰的绳军。
性能和不足
在性能上印机,HanziToPinyin還是比較客觀的矢腻,畢竟用了二分檢索,在實際測試過程中丟了一篇5500多字的文章進行轉換射赛,只用了415ms多柑;
在準確率上,拿了一堆人名和一個國家列表數據進行轉換楣责,隨機抽取數據都沒有發(fā)現(xiàn)出錯的數據竣灌,但是按照這個類的實現(xiàn)上看,如果輸入的漢字拼音不與UNIHANS中任何一個元素同音秆麸,則必然無法得到正確的結果初嘹,實際測試中,我隨便拿了一些數據測試都沒有得到不正確的結果輸出沮趣,不知道得多生僻的字才能得出個錯誤結果屯烦;
HanziToPinyin這類并不支持多音字,所以如果一定要考慮多音字的問題房铭,這個類就不適合了驻龟;
總結
關于HanziToPinyin就介紹到這里,我已經將這個類的代碼我已經整理放在Gist上(https://gist.github.com/D-clock/7a6e33f42c0177439a49d85b73f1e600)缸匪,需要的同學自取 翁狐,如果HanziToPinyin不能滿足你的需求,那可以考慮使用前面提到的pinyin4j和TinyPinyin凌蔬。