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

2017/08/16

一. 漢字轉拼音的現狀

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

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

具體到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了。

本文由 一點資訊 提供 原文連結

立即按讚,感謝大大無私地分享
寫了5860435篇文章,獲得22077
Line

熱門推薦

精彩推薦

什麼是火熱螺旋呢,看下面這個效果圖,這個就是今天小編給大家帶來的火熱螺旋!效果圖:火熱螺旋想不想這個是怎樣做成的呢?那麼下面小編就來告訴你,這個是怎麼做到的!分享之前我還是要推薦下我自己的前端新手...
百度神回復效果由75行javascript代碼和10行css代碼製作,有需要練習javascript的小夥伴可以用來練習。分享之前我還是要推薦下我自己的前端學習群:589651705,不管你是小白還是大牛,小編我都挺歡迎,不定期分享...
效果圖如下:上面圖片鍋打灰太狼效果就是我206行代碼的傑作,不是程序員之前很熱愛於這些小遊戲的,自從學習前端三個月,感覺自身有能力去寫代碼了,就做了這個鍋打灰太狼特效。代碼量也不是很多,主要以javascri...
今天小編我又給大家找到一個好玩的案例,css結合JavaScript畫一個MacBook,作品是一個找工作的小夥伴做的,發到論壇上,下面都是膜拜大佬的萌新留言,我也湊個熱鬧,COPY了一份,分享給頭條上的夥伴,看看,感受下...
我今天逛論壇,看到了一位大神級別程序員分享他的故事,小夥子畢業兩年,前端工作一年,原本工資8000想跳槽一家更高的,公司是一家做遊戲開發的,他成功進入公司,但凡都知道都有個實習期,也就是6個月實習期過後...
我們作為程序員很清楚自己每天做了些什麼,但你知道你一年敲了多少代碼嗎?你又進步了多少呢?今天逛論壇看到一位大神說他自己大約一年的代碼產量是20萬行。當時論壇里其他人表示不信,下來我們討論了一下20萬行...
程序員40行javascript代碼搞定這個特效,我已懵逼了效果有點小卡,來一張靜態的,感覺有點像小風扇哦什麼也不說了直接上源碼!需要更多的web前端企業級特效,學習方法可以到我的前端群524262608,不定期分享乾貨...
由於上傳圖片大小有限制,所以只能製作這樣質量的動圖,實際效果比這流暢很多!這粒子的打造,確實沒有布局代碼,稍後大家在源碼上可以看到,css代碼都只有幾行,絕大部分代碼都是javascript代碼,而且是原生java...
代碼畫出的蒙娜麗莎今天逛CODEPEN找HTML5動畫案例的時候,偶爾看到一位神級大師的作品,用純CSS代碼畫出一副蒙娜麗莎,雖然解析度不高,但是仍然讓我很是震撼,一看代碼,整整8000行,基本一行代碼就意味著一個像...
則回覆