Javascript實(shí)現(xiàn)漢字和拼音互轉(zhuǎn)的終極方案
前言
中文漢字和拼音互轉(zhuǎn)是很多地方都會(huì)遇到的,本文是精心整理并修改了網(wǎng)上幾種常見的字典文件并簡(jiǎn)單封裝了一下可以直接拿來用的工具庫。有需要的下面來一起看看。
漢字轉(zhuǎn)拼音:
拼音轉(zhuǎn)漢字:
漢字與拼音相關(guān)知識(shí)普及
漢字范圍
一般認(rèn)為Unicode編碼中的漢字范圍是 /^[\u2E80-\u9FFF]+$/ (11904-40959)
,但是其中有很多不是漢字,或者說是可以讀的漢字,本文用到的幾個(gè)字典文件的漢字范圍均是 /^[\u4E00-\u9FA5]+$/
,也就是(19968-40869),另外還有一個(gè)單獨(dú)的漢字〇,其Unicode位置是12295。
拼音組合
漢字有21個(gè)聲母:b, p, m, f, d, t, n, l, g, k, h, j, q, x, zh, ch, sh, r, z, c, s,24個(gè)韻母,其中單韻母有6個(gè):a, o, e, i, u, v, 復(fù)韻母有18個(gè):ai , ei, ui , ao, ou, iu , ie, ve, er, an , en , in, un , vn , ang, eng, ing , ong,假設(shè)聲母和韻母兩兩組合的話,會(huì)有24X21=504種組合,實(shí)際情況是有些組合是沒有意義的,比如bv, gie, ve等,去除這部分后,還剩余412種。
拼音字典文件
按照字典文件的大小從小到大依次介紹。
字典一:拼音首字母
該 字典文件 的內(nèi)容大致如下:
/** * 拼音首字母字典文件 */ var pinyin_dict_firstletter = {}; pinyin_dict_firstletter.all = "YDYQSXMWZSSXJBYMGCCZQPSSQBYCDSCDQLDYLYBSSJG..."; pinyin_dict_firstletter.polyphone = {"19969":"DZ","19975":"WM","19988":"QJ","20048":"YL",...};
該數(shù)據(jù)字典將Unicode字符中 4E00 (19968)- 9FA5 (40869)共計(jì)20902個(gè)漢字的拼音首字母拼接在一起得到一個(gè)很長(zhǎng)的字符串,然后再將有多音字的漢字(共計(jì)370個(gè)多音字)單獨(dú)列出來。該字典文件大小為 25kb 。
該字典文件優(yōu)點(diǎn)是體積小,支持多音字,缺點(diǎn)是只能獲取拼音首字母。
字典二:常用漢字
該字典文件將漢字按照拼音進(jìn)行歸類,共計(jì)401種組合,收錄了6763個(gè)常用漢字,不支持多音字。由于從網(wǎng)絡(luò)上收集的,收錄字?jǐn)?shù)較少,所以文件體積只有24kb,后續(xù)有空看能不能給擴(kuò)充一下。
字典文件大致內(nèi)容如下(這里只是示例,所以只展示一小部分):
/** * 常規(guī)拼音數(shù)據(jù)字典,收錄常見漢字6763個(gè),不支持多音字 */ var pinyin_dict_notone = { "a":"啊阿錒", "ai":"埃挨哎唉哀皚癌藹矮艾礙愛隘誒捱噯嗌嬡璦曖砹锿靄", "an":"鞍氨安俺按暗岸胺案諳埯揞犴庵桉銨鵪頇黯", "ang":"骯昂盎", "ao":"凹敖熬翱襖傲奧懊澳坳拗嗷噢岙廒遨媼驁聱螯鏊鰲鏖", "ba":"芭捌扒叭吧笆八疤巴拔跋靶把耙壩霸罷爸茇菝萆捭岜灞杷鈀粑鲅魃", "bai":"白柏百擺佰敗拜稗薜掰鞴", "ban":"斑班搬扳般頒板版扮拌伴瓣半辦絆阪坂豳鈑瘢癍舨", "bang":"邦幫梆榜膀綁棒磅蚌鎊傍謗蒡螃", "bao":"苞胞包褒雹保堡飽寶抱報(bào)暴豹鮑爆勹葆宀孢煲鴇褓趵齙", "bo":"剝薄玻菠播撥缽波博勃搏鉑箔伯帛舶脖膊渤泊駁亳蕃啵餑檗擘礴鈸鵓簸跛", "bei":"杯碑悲卑北輩背貝鋇倍狽備憊焙被孛陂邶埤蓓唄怫悖碚鵯褙鐾", "ben":"奔苯本笨畚坌錛" // 省略其它 };
后來慢慢發(fā)現(xiàn)這個(gè)字典文件中存在諸多錯(cuò)誤,比如把 虐 的拼音寫成了 nue (正確寫法應(yīng)該是nve), 躺 寫成了 thang ,而且不支持多音字,所以后來我根據(jù)其它字典文件自己重新生成了一份這樣格式的 字典文件 :
共有404種拼音組合
收錄了6763個(gè)常用漢字
支持多音字
不支持聲調(diào)
文件大小為27kb
同時(shí),我根據(jù)網(wǎng)上一份 常用6763個(gè)漢字使用頻率表 ,將這6763個(gè)漢字按照使用頻率進(jìn)行了排序,這樣就可以實(shí)現(xiàn)一個(gè)差強(qiáng)人意的JS版輸入法了。
另外,根據(jù)另外一份更完整的字典文件發(fā)現(xiàn)其實(shí)共有412種拼音組合,上面字典文件中沒有出現(xiàn)的8種發(fā)音是:
chua,den,eng,fiao,m,kei,nun,shei
字典三:終極字典
首先,從網(wǎng)上找的如下結(jié)構(gòu)字典文件(下面稱為字典A),具體是哪不記得了,支持聲調(diào)和多音字,它將Unicode字符中 4E00 (19968)- 9FA5 (40869)共計(jì)20902個(gè)漢字(如果算上〇的話那就是20903個(gè))拼音全部列舉,該字典文件大小為 280kb :
3007 (ling2) 4E00 (yi1) 4E01 (ding1,zheng1) 4E02 (kao3) 4E03 (qi1) 4E04 (shang4,shang3) 4E05 (xia4) 4E06 (none0) 4E07 (wan4,mo4) 4E08 (zhang4) 4E09 (san1) 4E0A (shang4,shang3) 4E0B (xia4) 4E0C (ji1) 4E0D (bu4,bu2,fou3) 4E0E (yu3,yu4,yu2) 4E0F (mian3) 4E10 (gai4) 4E11 (chou3) 4E12 (chou3) 4E13 (zhuan1) 4E14 (qie3,ju1) ...
其中,對(duì)于沒有或者找不到讀音的漢字,統(tǒng)一標(biāo)注為 none0 ,我統(tǒng)計(jì)了一下,這樣的漢字一共有525個(gè)。
本著將字典文件盡可能減小體積的目標(biāo),發(fā)現(xiàn)上述文件中除了第一個(gè)〇(3007)之外,其它都是連續(xù)的,所以我把它改成了如下結(jié)構(gòu),文件體積也從 280kb 減小到了 117kb :
var pinyin_dict_withtone = "yi1,ding1 zheng1,kao3,qi1,shang4 shang3,xia4,none0,wan4 mo4,zhang4,san1,shang4 shang3,xia4,ji1,bu4 bu2 fou3,yu3 yu4 yu2,mian3,gai4,chou3,chou3,zhuan1,qie3 ju1...";
該字典文件的缺點(diǎn)是聲調(diào)是用數(shù)字標(biāo)出的,如果想要得出類似 xiǎo míng tóng xué
這樣的拼音的話,需要一個(gè)算法將合適位置的字母轉(zhuǎn)換成 āáǎàōóǒòēéěèīíǐìūúǔùüǖǘǚǜńň
。
本來還準(zhǔn)備自己嘗試寫一個(gè)轉(zhuǎn)換的方法的,后來又找到了如下 字典文件 (下面稱為字典B),它收錄了20867個(gè)漢字,也支持聲調(diào)和多音字,但是聲調(diào)是直接標(biāo)在字母上方的,由于它將漢字也列舉出來,所以文件體積比較大,有 327kb ,大致內(nèi)容如下:
{ "吖": "yā,ā", "阿": "ā,ē", "呵": "hē,a,kē", "嗄": "shà,á", "啊": "ā,á,ǎ,à,a", "腌": "ā,yān", "錒": "ā", "錒": "ā", "矮": "ǎi", "愛": "ài", "挨": "āi,ái", "哎": "āi", "礙": "ài", "癌": "ái", "艾": "ài", "唉": "āi,ài", "藹": "ǎi" /* 省略其它 */ }
但是經(jīng)過比對(duì),發(fā)現(xiàn)有502個(gè)漢字是字典A中讀音為 none 但是字典B中有讀音的,還有21個(gè)漢字是字典A中有但是B中沒有的:
{ "兙": "shí kè", "兛": "qiān", "兝": "fēn", "兞": "máo", "兡": "bǎi kè", "兣": "lǐ", "唞": "dǒu", "嗧": "jiā lún", "囍": "xǐ", "堎": "lèng líng", "猤": "hú", "瓩": "qián wǎ", "礽": "réng", "膶": "rùn", "芿": "rèng", "蟘": "tè", "貣": "tè", "釀": "niàng niàn niáng", "醸": "niàng", "鋱": "tè", "鋱": "tè" }
還有7個(gè)漢字是B中有但是A中沒有的:
{ "㘄": "lēng", "䉄": "léng", "䬋": "léng", "䮚": "lèng", "䚏": "lèng,lì,lìn", "㭁": "réng", "䖆": "niàng" }
所以我在字典A的基礎(chǔ)上將二者進(jìn)行了合并,得到了最終的字典文件 pinyin_dict_withtone.js ,文件大小為 122kb :
var pinyin_dict_withtone = "yī,dīng zhēng,kǎo qiǎo yú,qī,shàng,xià,hǎn,wàn mò,zhàng,sān,shàng shǎng,xià,qí jī...";
如何使用
我將這幾種字典文件放在一起并簡(jiǎn)單封裝了一下解析方法,使用中可以根據(jù)實(shí)際需要引入不同字典文件。
封裝好的3個(gè)方法:
/** * 獲取漢字的拼音首字母 * @param str 漢字字符串,如果遇到非漢字則原樣返回 * @param polyphone 是否支持多音字,默認(rèn)false,如果為true,會(huì)返回所有可能的組合數(shù)組 */ pinyinUtil.getFirstLetter(str, polyphone); /** * 根據(jù)漢字獲取拼音,如果不是漢字直接返回原字符 * @param str 要轉(zhuǎn)換的漢字 * @param splitter 分隔字符,默認(rèn)用空格分隔 * @param withtone 返回結(jié)果是否包含聲調(diào),默認(rèn)是 * @param polyphone 是否支持多音字,默認(rèn)否 */ pinyinUtil.getPinyin(str, splitter, withtone, polyphone); /** * 拼音轉(zhuǎn)漢字,只支持單個(gè)漢字,返回所有匹配的漢字組合 * @param pinyin 單個(gè)漢字的拼音,不能包含聲調(diào) */ pinyinUtil.getHanzi(pinyin);
下面分別針對(duì)不同場(chǎng)合如何使用作介紹。
如果你只需要獲取拼音首字母
<script type="text/javascript" src="pinyin_dict_firstletter.js"></script> <script type="text/javascript" src="pinyinUtil.js"></script> <script type="text/javascript"> pinyinUtil.getFirstLetter('小茗同學(xué)'); // 輸出 XMTX pinyinUtil.getFirstLetter('大中國', true); // 輸出 ['DZG', 'TZG'] </script>
需要特別說明的是,如果你引入的是其它2個(gè)字典文件,也同樣可以獲取拼音首字母的,只是說用這個(gè)字典文件更適合。
如果拼音不需要聲調(diào)
<script type="text/javascript" src="pinyin_dict_noletter.js"></script> <script type="text/javascript" src="pinyinUtil.js"></script> <script type="text/javascript"> pinyinUtil.getPinyin('小茗同學(xué)'); // 輸出 'xiao ming tong xue' pinyinUtil.getHanzi('ming'); // 輸出 '明名命鳴銘冥茗溟酩瞑螟暝' </script>
如果需要聲調(diào)或者需要處理生僻字
<script type="text/javascript" src="pinyin_dict_withletter.js"></script> <script type="text/javascript" src="pinyinUtil.js"></script> <script type="text/javascript"> pinyinUtil.getPinyin('小茗同學(xué)'); // 輸出 'xiǎo míng tóng xué' pinyinUtil.getPinyin('小茗同學(xué)', '-', true, true); // 輸出 ['xiǎo-míng-tóng-xué', 'xiǎo-míng-tòng-xué'] </script>
關(guān)于簡(jiǎn)單拼音輸入法
一個(gè)正式的輸入法需要考慮的東西太多太多,比如詞庫、用戶個(gè)人輸入習(xí)慣等,這里只是實(shí)現(xiàn)一個(gè)最簡(jiǎn)單的輸入法,沒有任何詞庫(雖然加上也可以,但是web環(huán)境不適合引入太大的文件)。
推薦使用第二個(gè)字典文件 pinyin_dict_noletter.js ,雖然字典三字?jǐn)?shù)更多,但是不能按照漢字使用頻率排序,一些生僻字反而在前面。
<link rel="stylesheet" type="text/css" href="simple-input-method/simple-input-method.css"> <input type="text" class="test-input-method"/> <script type="text/javascript" src="pinyin_dict_noletter.js"></script> <script type="text/javascript" src="pinyinUtil.js"></script> <script type="text/javascript" src="simple-input-method/simple-input-method.js"></script> <script type="text/javascript"> SimpleInputMethod.init('.test-input-method'); </script>
總結(jié)
由于本工具類的目標(biāo)環(huán)境是web,而web注定了文件體積不能太大,所以不能引入太大的詞庫文件,由于沒有詞庫的支持,所以多音字無法識(shí)別,實(shí)現(xiàn)的拼音輸入法也無法智能地匹配出合適的詞語。以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來一定的幫助。
相關(guān)文章
JavaScript防抖與節(jié)流超詳細(xì)全面講解
在開發(fā)中我們經(jīng)常會(huì)遇到一些高頻操作,比如:鼠標(biāo)移動(dòng),滑動(dòng)窗口,鍵盤輸入等等,節(jié)流和防抖就是對(duì)此類事件進(jìn)行優(yōu)化,降低觸發(fā)的頻率,以達(dá)到提高性能的目的。本文就教大家如何實(shí)現(xiàn)一個(gè)讓面試官拍大腿的防抖節(jié)流函數(shù),需要的可以參考一下2022-10-10javascript 四則運(yùn)算精度修正函數(shù)代碼
JS預(yù)算精度問題確實(shí)很麻煩,這個(gè)能解決一些問題,雖然有bug.2010-05-05JS實(shí)現(xiàn)網(wǎng)頁搶購功能(觸發(fā),終止腳本)
小編通過一個(gè)網(wǎng)頁式的搶購功能的實(shí)現(xiàn)給大家講解一下JS如何觸發(fā)和終止腳本來完成這個(gè)任務(wù)。2017-11-11javascript異常處理實(shí)現(xiàn)原理詳解
這篇文章主要介紹了javascript異常處理實(shí)現(xiàn)原理詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02基于cornerstone.js的dicom醫(yī)學(xué)影像查看瀏覽功能
這篇文章主要介紹了基于cornerstone.js的dicom醫(yī)學(xué)影像查看瀏覽功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-07-07JavaScript常用8種數(shù)組去重代碼實(shí)例
這篇文章主要介紹了JavaScript常用8種數(shù)組去重代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09JavaScript構(gòu)造函數(shù)原理及實(shí)現(xiàn)流程解析
這篇文章主要介紹了JavaScript構(gòu)造函數(shù)原理及實(shí)現(xiàn)流程解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11