網路上關於JS實現漢字和拼音互轉的文章很多,但是比較雜亂,都是互相抄來抄去,而且有的不支援多音字,有的不支援聲調,有的字典文件太大,還例如有時候我僅僅是需要獲取漢字拼音首字母卻要引入200kb的字典文件,無法根據實際需要滿足需求。
綜上,我精心整理並修改了網路上幾種常見的字典檔案並簡單封裝了一下可以直接拿來用的工具庫。
github專案網址:https://github.com/liuxianan/pinyinjs
完整demo演示:http://demo.liuxianan.com /pinyinjs/
漢字轉拼音:
# 轉漢字:
一般認為Unicode編碼中的漢字範圍是 /^[\u2E80-\u9FFF]+$/
(11904-40959),但其中有許多不是漢字,或者說是可以讀的漢字,本文用到的幾個字典文件的漢字範圍都是 /^[\u4E00-\u9FA5]+$/
,也就是( 19968-40869),另外還有一個單獨的漢字〇,其Unicode位置是12295。
漢字有21個聲母:b, p, m, f, d, t, n, l, g, k, h, j, q, x, zh, ch, sh, r, z, c, s,24個韻母,其中單韻母有6個:a, o, e, i, u, v, 複韻母有18個:ai , ei, ui , ao, ou , iu , ie, ve, er, an , en , in, un , vn , ang, eng, ing , ong,假設聲母和韻母兩兩組合的話,會有24X21=504種組合,實際情況是有些組合是沒有意義的,如bv, gie, ve等,去除這部分後,還剩餘412種。
依照字典檔案的大小從小到大依序介紹。
該字典檔案的內容大致如下:
/** * 拼音首字母字典文件 */ var pinyin_dict_firstletter = {}; pinyin_dict_firstletter.all = "YDYQSXMWZSSXJBYMGCCZQPSSQBYCDSCDQLDYLYBSSJG..."; pinyin_dict_firstletter.polyphone = {"19969":"DZ","19975":"WM","19988":"QJ","20048":"YL",...};
該資料字典將Unicode字元中4E00
(19968) -9FA5
(40869)共計20902個漢字的拼音首字母拼接在一起得到一個很長的字串,然後再將有多音字的漢字(共370個多音字)單獨列出來。該字典檔案大小為25kb
。
此字典檔案優點是體積小,支援多音字,缺點是只能取得拼音首字母。
此字典檔案將漢字依照拼音進行歸類,共401種組合,收錄了6763個常用漢字,不支援多音字。由於從網路上收集的,收錄字數較少,所以檔案體積只有24kb,後續有空看能不能給擴充一下。
字典檔案大致內容如下(這裡只是範例,所以只展示一小部分):
/** * 常规拼音数据字典,收录常见汉字6763个,不支持多音字 */ var pinyin_dict_notone = { "a":"啊阿锕", "ai":"埃挨哎唉哀皑癌蔼矮艾碍爱隘诶捱嗳嗌嫒瑷暧砹锿霭", "an":"鞍氨安俺按暗岸胺案谙埯揞犴庵桉铵鹌顸黯", "ang":"肮昂盎", "ao":"凹敖熬翱袄傲奥懊澳坳拗嗷噢岙廒遨媪骜聱螯鏊鳌鏖", "ba":"芭捌扒叭吧笆八疤巴拔跋靶把耙坝霸罢爸茇菝萆捭岜灞杷钯粑鲅魃", "bai":"白柏百摆佰败拜稗薜掰鞴", "ban":"斑班搬扳般颁板版扮拌伴瓣半办绊阪坂豳钣瘢癍舨", "bang":"邦帮梆榜膀绑棒磅蚌镑傍谤蒡螃", "bao":"苞胞包褒雹保堡饱宝抱报暴豹鲍爆勹葆宀孢煲鸨褓趵龅", "bo":"剥薄玻菠播拨钵波博勃搏铂箔伯帛舶脖膊渤泊驳亳蕃啵饽檗擘礴钹鹁簸跛", "bei":"杯碑悲卑北辈背贝钡倍狈备惫焙被孛陂邶埤蓓呗怫悖碚鹎褙鐾", "ben":"奔苯本笨畚坌锛" // 省略其它 };
後來慢慢發現這個字典檔案中存在諸多錯誤,例如把虐
的拼音寫成了nue
(正確寫法應該是nve),躺
#寫成了thang
,而且不支持多音字,所以後來我根據其它字典文件自己重新產生了一份這樣格式的 字典檔:
共有404種拼音組合
收錄了6763個常用漢字
支援多音字
不支援聲調
檔案大小為27kb
同時,我根據網路上一份常用6763個漢字使用頻率表,將這6763個漢字按照使用頻率進行了排序,這樣就可以實現一個差強人意的JS版輸入法了。
另外,根據另外一份更完整的字典檔案發現其實共有412種拼音組合,上面字典檔案中沒有出現的8種發音是:
chua,den,eng,fiao,m,kei,nun,shei
首先,從網路上找的如下結構字典檔案(下面稱為字典A),具體是哪不記得了,支援聲調和多音字,它將Unicode字元中4E00
(19968 )-9FA5
(40869)共計20902個漢字(如果算上〇的話那就是20903個)拼音全部列舉,該字典檔案大小為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) ...
#其中,對於沒有或找不到讀音的漢字,統一標註為none0
,我統計了一下,這樣的漢字一共有525個。
本著將字典檔案盡可能減少體積的目標,發現上述文件中除了第一個〇(3007)之外,其它都是連續的,所以我把它改成瞭如下結構,檔案體積也從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...";
該字典檔案的缺點是聲調是用數字標出的,如果想要得出類似xiǎo míng tóng xué
這樣的拼音的話,需要一個演算法將合適位置的字母轉換成āáǎàōóǒòēéěèīíǐìūúǔùüǖǘǚǜńň
。
本来还准备自己尝试写一个转换的方法的,后来又找到了如下字典文件(下面称为字典B),它收录了20867个汉字,也支持声调和多音字,但是声调是直接标在字母上方的,由于它将汉字也列举出来,所以文件体积比较大,有327kb
,大致内容如下:
{ "吖": "yā,ā", "阿": "ā,ē", "呵": "hē,a,kē", "嗄": "shà,á", "啊": "ā,á,ǎ,à,a", "腌": "ā,yān", "锕": "ā", "錒": "ā", "矮": "ǎi", "爱": "ài", "挨": "āi,ái", "哎": "āi", "碍": "ài", "癌": "ái", "艾": "ài", "唉": "āi,ài", "蔼": "ǎi" /* 省略其它 */ }
但是经过比对,发现有502个汉字是字典A中读音为none
但是字典B中有读音的,还有21个汉字是字典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个汉字是B中有但是A中没有的:
{ "㘄": "lēng", "䉄": "léng", "䬋": "léng", "䮚": "lèng", "䚏": "lèng,lì,lìn", "㭁": "réng", "䖆": "niàng" }
所以我在字典A的基础上将二者进行了合并,得到了最终的字典文件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ī...";
我将这几种字典文件放在一起并简单封装了一下解析方法,使用中可以根据实际需要引入不同字典文件。
封装好的3个方法:
/** * 获取汉字的拼音首字母 * @param str 汉字字符串,如果遇到非汉字则原样返回 * @param polyphone 是否支持多音字,默认false,如果为true,会返回所有可能的组合数组 */ pinyinUtil.getFirstLetter(str, polyphone); /** * 根据汉字获取拼音,如果不是汉字直接返回原字符 * @param str 要转换的汉字 * @param splitter 分隔字符,默认用空格分隔 * @param withtone 返回结果是否包含声调,默认是 * @param polyphone 是否支持多音字,默认否 */ pinyinUtil.getPinyin(str, splitter, withtone, polyphone); /** * 拼音转汉字,只支持单个汉字,返回所有匹配的汉字组合 * @param pinyin 单个汉字的拼音,不能包含声调 */ pinyinUtil.getHanzi(pinyin);
下面分别针对不同场合如何使用作介绍。
<script type="text/javascript" src="pinyin_dict_firstletter.js"></script> <script type="text/javascript" src="pinyinUtil.js"></script> <script type="text/javascript"> pinyinUtil.getFirstLetter('小茗同学'); // 输出 XMTX pinyinUtil.getFirstLetter('大中国', true); // 输出 ['DZG', 'TZG'] </script>
需要特别说明的是,如果你引入的是其它2个字典文件,也同样可以获取拼音首字母的,只是说用这个字典文件更适合。
<script type="text/javascript" src="pinyin_dict_noletter.js"></script> <script type="text/javascript" src="pinyinUtil.js"></script> <script type="text/javascript"> pinyinUtil.getPinyin('小茗同学'); // 输出 'xiao ming tong xue' pinyinUtil.getHanzi('ming'); // 输出 '明名命鸣铭冥茗溟酩瞑螟暝' </script>
<script type="text/javascript" src="pinyin_dict_withletter.js"></script> <script type="text/javascript" src="pinyinUtil.js"></script> <script type="text/javascript"> pinyinUtil.getPinyin('小茗同学'); // 输出 'xiǎo míng tóng xué' pinyinUtil.getPinyin('小茗同学', '-', true, true); // 输出 ['xiǎo-míng-tóng-xué', 'xiǎo-míng-tòng-xué'] </script>
一个正式的输入法需要考虑的东西太多太多,比如词库、用户个人输入习惯等,这里只是实现一个最简单的输入法,没有任何词库(虽然加上也可以,但是web环境不适合引入太大的文件)。
推荐使用第二个字典文件pinyin_dict_noletter.js
,虽然字典三字数更多,但是不能按照汉字使用频率排序,一些生僻字反而在前面。
<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>
由于本工具类的目标环境是web,而web注定了文件体积不能太大,所以不能引入太大的词库文件,由于没有词库的支持,所以多音字无法识别,实现的拼音输入法也无法智能地匹配出合适的词语,需要词库支持的可以参考这个nodejs环境下的项目:http://www.php.cn/
以上就是JavaScript 汉字与拼音互转终极方案 附JS拼音输入法的详细介绍的内容,更多相关内容请关注PHP中文网(www.php.cn)!