search
尋找貓咪~QQ 地點 桃園市桃園區 Taoyuan , Taoyuan

神級程序員JavaScript300行代碼搞定漢字轉拼音

一. 漢字轉拼音的現狀

首先應該說,漢字轉拼音是個強需求,比如聯繫人按拼音字母排序/篩選;比如目的地(典型如機票購買)

按拼音首字母分類等等。但是這個需求的解決方案,但好像沒聽過什麼巧妙的實現(特別是瀏覽器端),大概都需要一個龐大的字典。

具體到JavaScript,查查github和npm,比較優秀的處理漢字轉拼音的庫有pinyinpinyinjs,可以看到,兩者都自帶了龐大的字典。

這些字典動輒幾十上百KB(有的甚至幾MB),想在瀏覽器端使用還是需要一些勇氣的。所以當我們碰到漢字轉拼音的需求,也不怪我們第一反應就是拒絕需求(或者服務端實現)。

現在,如果我告訴你可以瀏覽器端 300 行代碼實現漢字轉拼音,是不是不可置信?

二. 從安卓4.2.2聯繫人代碼說起

再次強調這篇博客——利用Android源碼,輕鬆實現漢字轉拼音功能。

今天和大家分享一個從Android系統源代碼提取出來的漢字轉成拼音實現方案,只要一個類,560多行代碼就可以讓你輕鬆實現漢字轉成拼音的功能,且無需其他任何第三方依賴。

是不是打破了你的思維定勢:難道有什麼強大的演算法可以拋棄字典?

第一遍看完博客,稍有些失望,並沒有什麼演算法解析,只是介紹了從安卓代碼發現的這幾百行代碼。第二遍時帶著移植到JavaScript的想法閱讀代碼,算是弄懂了原理,於是開始了踩坑的移植之旅。

三. 手把手教你 300 行JavaScript代碼實現漢字轉拼音

首先直指核心:為什麼有漢字轉拼音必須有龐大字典的思維定勢?

因為漢字的排布和拼音並有什麼關聯,比如在漢字區間一-鿿,前一個可能是ha,后一個可能就是ze,沒有辦法從漢字的unicode關聯到拼音,所以只能有一個龐大的字典記錄每個漢字(或常用漢字)的拼音。

但是,假設我們可以把所有漢字按拼音排序,比如按'A', 'AI', 'AN', 'ANG', 'AO', 'BA',...,'ZUI', 'ZUN', 'ZUO'排序,那麼,我們只需要記住每個相同拼音的漢字隊列的第一個漢字就好了。那麼,所需要的字典就會很小(覆蓋所有拼音即可,拼音數量本身不多)。

現在,難點就是把漢字按拼音排序了。很幸運,ICU/本地化相關的API提供了這個排序API(如果沒有方便的排序/比較方法,那麼本篇文章可能就不會出現了)。

所以,這就是為什麼 300 行可以實現漢字轉拼音:Intl.Collator API:Intl.Collator內部實現了本土化相關的字元串排序。我們通過Intl.Collator.prototype.compare可以把所有漢字 基本 按照拼音來排序。

邊界漢字表:記錄了排序的邊界點。該漢字表的每個漢字都是排序后相同拼音的漢字集合的首個漢字(Each unihans is the first one within same pinyin when collator is zh_CN)。

如果想要更多的企業求職加分項目,案例,學習方法可以來一下我的前端群657-137-906,每天都會精挑細選一個特效,項目出來詳細講解,分享!包括答疑解惑!

說到這裡,可能仍然有沒說清楚的地方,所以直接上一段代碼:

有興趣的同學可以執行node --icu-data-dir=node_modules/full-icu 上面的腳本.js看看,然後看看是不是得到了 基本 按照拼音排序的漢字表。

這裡有幾點要注意:

我再次加粗了 「基本」 ,因為我們得到的漢字列表並沒有完全按照拼音來排序,中間偶爾有一些其它拼音的漢字插入,這點在製作 邊界表 時要額外注意。

上面腳本里得出的表是所有漢字的排序,其中有些和安卓代碼里HanziToPinyin.java的表有不同,所以需要更新HanziToPinyin.java的表。(從Java轉到JavaScript的最大的坑和工作量:更正邊界表)

相信大家都看到了核心代碼:const COLLATOR = new Intl.Collator(['zh-Hans-CN'])Intl.Collator(這裡指定locale是zh-Hans-CN)正是能把漢字按拼音排序的關鍵,它是按locale-specific順序,排序字元串的Internationalization API。

執行腳本時請先npm i full-icu,這個依賴會自動安裝缺失的中文支持並提示如何指定ICU數據文件來執行腳本。

1. ICUICU即International Components for Unicode,為應用提供Unicode和國際化支持。

ICU is a mature, widely used set of C/C++ and Java libraries providing Unicode and Globalization support for software applications. ICU is widely portable and gives applications the same results on all platforms and between C/C++ and Java software.

並且 ICU 提供了本地化字元串比較服務(Unicode Collation Algorithm + 本地特定的比較規則):

Collation: Compare strings according to the conventions and standards of a particular language, region or country. ICU's collation is based on the Unicode Collation Algorithm plus locale-specific comparison rules from the Common Locale Data Repository, a comprehensive source for this type of data.

在現代瀏覽器上,一般ICU內置了對用戶本地語言的支持,我們直接使用即可。

但對node.js來說,通常情況下,ICU只包含了一個子集(通常是英語),所以我們需要自行添加對中文的支持。一般來說,可以通過npm install full-icu安裝full-icu來安裝缺失的中文支持。(參見上面node --icu-data-dir=node_modules/full-icu)。

2. Intl API上一小節應該基本講清楚了國際化/本地化相關的知識,這裡再補充一下內置API的使用。怎麼查看用戶語言和Runtime是否支持這個語言?Intl.Collator.supportedLocalesOf(array|string)

返回包含支持(不用回退到默認locale)的locales的數組,參數可以是數組或字元串,為想要測試的locales(即BCP 47 language tag)。

構造Collator對象和排序字元串

通過Intl.Collator.prototype.compare,我們可以按語言指定的順序來排序字元串。而中文中,這個排序恰好絕大多數都是按拼音的順序來的,'A', 'AI', 'AN', 'ANG', 'AO', 'BA', 'BAI', 'BAN', 'BANG', 'BAO', 'BEI', 'BEN', 'BENG', 'BI', 'BIAN', 'BIAO', 'BIE', 'BIN', 'BING', 'BO', 'BU', 'CA', 'CAI', 'CAN', ...,這正是我們上面提到的漢字轉拼音的關鍵。

四. 邊界表更正

顯然,這個邊界表是有問題的,需要更正。

我們可看到,大部分的漢字被轉成了qing,可見,qing這個拼音對應的漢字有問題。

找到這個漢字,是 '狅'/'狅',加上前後各一個字,['親', '狅', '芎']/["親", "狅", "芎"]

搜索,'狅'/'狅'可以讀qing,但現在多讀kuang,這應該就是錯誤的原因了。

根據最初得到那張所有漢字的排序表,qing的第一個漢字是'靑'/'靑'

改動后,轉換失敗的只剩104了。



熱門推薦

本文由 yidianzixun 提供 原文連結

寵物協尋 相信 終究能找到回家的路
寫了7763篇文章,獲得2次喜歡
留言回覆
回覆
精彩推薦