Javascript实现汉字和拼音互转的终极方案


Posted in Javascript onOctober 19, 2016

前言

中文汉字和拼音互转是很多地方都会遇到的,本文是精心整理并修改了网上几种常见的字典文件并简单封装了一下可以直接拿来用的工具库。有需要的下面来一起看看。

汉字转拼音:

Javascript实现汉字和拼音互转的终极方案

拼音转汉字:

Javascript实现汉字和拼音互转的终极方案

汉字与拼音相关知识普及

汉字范围

一般认为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ǐ",
 "?z": "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注定了文件体积不能太大,所以不能引入太大的词库文件,由于没有词库的支持,所以多音字无法识别,实现的拼音输入法也无法智能地匹配出合适的词语。以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助。

Javascript 相关文章推荐
javascript this用法小结
Dec 19 Javascript
js event事件的传递与冒泡处理
Dec 06 Javascript
跨浏览器开发经验总结(四) 怎么写入剪贴板
May 13 Javascript
一个简单的网站访问JS计数器 刷新1次加1次访问
Sep 20 Javascript
js使浏览器窗口最大化实现代码(适用于IE)
Aug 07 Javascript
JS中for循序中延迟加载动态效果的具体实现
Aug 18 Javascript
js 动态修改css文件用到了cssRule
Aug 20 Javascript
ES6实现的遍历目录函数示例
Apr 07 Javascript
详解关于Vue2.0路由开启keep-alive时需要注意的地方
Sep 18 Javascript
帮你彻底搞懂JS中的prototype、__proto__与constructor(图解)
Aug 23 Javascript
浅谈vue异步数据影响页面渲染
Oct 29 Javascript
JS常见错误(Error)及处理方案详解
Jul 02 Javascript
Javascript typeof与instanceof的区别
Oct 18 #Javascript
javascript self对象使用详解
Oct 18 #Javascript
jQuery动态添加与删除tr行实例代码
Oct 18 #Javascript
Jquery表单验证失败后不提交的解决方法
Oct 18 #Javascript
vue.js 表格分页ajax 异步加载数据
Oct 18 #Javascript
vue.js表格分页示例
Oct 18 #Javascript
Angular.js中用ng-repeat-start实现自定义显示
Oct 18 #Javascript
You might like
PHP 判断变量类型实现代码
2009/10/23 PHP
php实现批量下载百度云盘文件例子分享
2014/04/10 PHP
php实现json编码的方法
2015/07/30 PHP
PHP时间类完整实例(非常实用)
2015/12/25 PHP
PHP的RSA加密解密方法以及开发接口使用
2018/02/11 PHP
javascript 带有滚动条的表格,标题固定,带排序功能.
2009/11/13 Javascript
juqery 学习之五 文档处理 包裹、替换、删除、复制
2011/02/11 Javascript
jQuery EasyUI API 中文文档 - Dialog对话框
2011/11/15 Javascript
js重写alert控件(适合学习js的新手朋友)
2014/08/24 Javascript
express的中间件cookieParser详解
2014/12/04 Javascript
node.js中的buffer.write方法使用说明
2014/12/10 Javascript
js滚动条平滑移动示例代码
2016/03/29 Javascript
jquery请求servlet实现ajax异步请求的示例
2017/06/03 jQuery
JavaScript+CSS相册特效实例代码
2017/09/07 Javascript
基于react后端渲染模板引擎noox发布使用
2018/01/11 Javascript
jsonp跨域及实现百度首页联想功能的方法
2018/08/30 Javascript
详解Vue项目中实现锚点定位
2019/04/24 Javascript
中高级前端必须了解的JS中的内存管理(推荐)
2019/07/04 Javascript
JS表单验证插件之数据与逻辑分离操作实例分析【策略模式】
2020/05/01 Javascript
从源码角度来回答keep-alive组件的缓存原理
2021/01/18 Javascript
[42:11]TNC vs Pain 2018国际邀请赛小组赛BO2 第二场 8.17
2018/08/20 DOTA
使用IPython来操作Docker容器的入门指引
2015/04/08 Python
Python中常用的内置方法
2019/01/28 Python
django中ORM模型常用的字段的使用方法
2019/03/05 Python
python 列表、字典和集合的添加和删除操作
2019/12/16 Python
Python之Class&amp;Object用法详解
2019/12/25 Python
python 写一个水果忍者游戏
2021/01/13 Python
HTML5 canvas画图并保存成图片的jcanvas插件
2014/01/17 HTML / CSS
HTML5手机端弹出遮罩菜单特效代码
2016/01/27 HTML / CSS
KIKO MILANO荷兰网上商店:意大利专业化妆品品牌
2017/05/12 全球购物
女大学生个人求职信
2013/12/09 职场文书
2014年国培研修感言
2014/03/09 职场文书
天猫活动策划方案
2014/08/21 职场文书
2014年国庆节演讲稿精选范文1500字
2014/09/25 职场文书
关于拾金不昧的感谢信(五篇)
2019/10/18 职场文书
python单元测试之pytest的使用
2021/06/07 Python