原文:http://www.cnblogs.com/liuxianan/p/pinyinjs.html

前言

网上关于JS实现汉字和拼音互转的文章很多,但是比较杂乱,都是互相抄来抄去,而且有的不支持多音字,有的不支持声调,有的字典文件太大,还比如有时候我仅仅是需要获取汉字拼音首字母却要引入200kb的字典文件,无法根据实际需要满足需求。

综上,我精心整理并修改了网上几种常见的字典文件并简单封装了一下可以直接拿来用的工具库。

这篇文章差不多一个月前就写好了大部分了,但是就差拼音输入法这一块一直没时间去弄(与其说是没时间,还不如说是本人太懒),所以一直拖到今天才发表。

代码和DEMO演示

github项目地址:https://github.com/liuxianan/pinyinjs

完整demo演示:http://demo.liuxianan.com/pinyinjs/

带多音字识别的演示:http://demo.liuxianan.com/pinyinjs/polyphone.html

汉字转拼音:

带词库的识别多音字的汉字转拼音:

拼音转汉字(简单的拼音输入法):

关于多音字

鉴于很多人都比较关心多音字的问题,所以单独拿出一个小章节来介绍多音字的相关问题。

准确识别各种复杂语句中混杂的多音字其实并没有那么容易,有两个关键的地方,一个是多音字词库的丰富程度,一个是能否正确的给语句进行分词。而词库和分词的实现都需要一个非常丰富的词典文件,现代汉语词语有多少个,估计没有人算得清,再加上每天新出现的人名、网络词语、科技词语等等。一个普通的词库文件至少也有几百kb,所以不太适合web环境下去实现,一般最好放在服务器端做成一个接口。

鉴于很多人都希望有多音字识别的功能,所以我简单实现了一个版本。词库文件是从这里找到的,并根据实际情况将文件从1.8M压缩到了912kb,分词暂时只是自己非常简单的实现(也可以说压根就没有分词),如果是服务器端推荐几个不错的中文分词工具:Python版的JiebaNodeJieba,性能非常好,其它语言版的参考上面项目的README。

关于分词,摘抄一段网络解释:

词是最小的能够独立活动的有意义的语言成分,英文单词之间是以空格作为自然分界符的,而汉语是以字为基本的书写单位,词语之间没有明显的区分标记,因此,要对中文信息进行处理,正确的分词就显得尤为关键。

比如看中国这一个词,单独的看中kàn zhòng中国zhōng guó,连在一起却读作kàn zhōng guó

我这个实现非常得简单,效果一般,性能也一般,需要下载将近1M的词库文件,所以不适合web环境,演示地址:

http://demo.liuxianan.com/pinyinjs/polyphone.html

汉字与拼音相关知识普及

汉字范围

一般认为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环境下的项目:https://github.com/hotoo/pinyin

JS版汉字与拼音互转终极方案,附简单的JS拼音输入法的更多相关文章

  1. JavaScript 汉字与拼音互转终极方案 附JS拼音输入法

    转:http://www.codeceo.com/article/javascript-pinyin.html 前言 网上关于JS实现汉字和拼音互转的文章很多,但是比较杂乱,都是互相抄来抄去,而且有的 ...

  2. 【干货】JS版汉字与拼音互转终极方案,附简单的JS拼音输入法

    前言 网上关于JS实现汉字和拼音互转的文章很多,但是比较杂乱,都是互相抄来抄去,而且有的不支持多音字,有的不支持声调,有的字典文件太大,还比如有时候我仅仅是需要获取汉字拼音首字母却要引入200kb的字 ...

  3. JS版汉字与拼音互转终极方案,附简单的JS拼音

    前言 网上关于JS实现汉字和拼音互转的文章很多,但是比较杂乱,都是互相抄来抄去,而且有的不支持多音字,有的不支持声调,有的字典文件太大,还比如有时候我仅仅是需要获取汉字拼音首字母却要引入200kb的字 ...

  4. js汉字与拼音互转终极方案,附简单的JS拼音输入法【转】

    github项目地址:https://github.com/liuxianan/pinyinjs 完整demo演示:http://demo.liuxianan.com/pinyinjs/ 汉字转拼音: ...

  5. js/jq基础(日常整理记录)-2-一个简单的js方法实现集合的非引用拷贝

    一.一个简单的js方法实现集合拷贝 做web项目的时候,少不了和js中的数组,集合等对象接触,那么你肯定会发现,在js中存在一个怪异的现象就是数组和集合的拷贝都是地址复制,并不是简单的数据的拷贝. 举 ...

  6. Twitter面试题蓄水池蓄水量算法(原创 JS版,以后可能会补上C#的)

    之前在群里有人讨论Twitter的面试题,蓄水池蓄水量计算,于是自己写了个JS版的(PS:主要后台代码还要编译,想想还是JS快,于是就使用了JS了.不过算法主要还是思路嘛,而且JS应该都没问题吧^_^ ...

  7. js中文汉字按拼音排序

    JavaScript 提供本地化文字排序,比如对中文按照拼音排序,不需要程序显示比较字符串拼音. String.prototype.localeCompare 在不考虑多音字的前提下,基本可以完美实现 ...

  8. js将汉字转为相应的拼音

    <!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8&quo ...

  9. 用JS实现汉字转拼音

    <!DOCTYPE HTML> <html> <head> <title>用JS实现汉字转拼音</title> <meta chars ...

随机推荐

  1. import as from import 区别

    在python中import或者from…import是用来导入相应的模块.那每一种有什么具体的差别呢? 一.import        只有import,为最简单的引入对应的包.例如: import ...

  2. Idea导入的工程看不到src等代码

    问题描述: 从其他地方拷贝过来的工程,在本地导入到idea中时,展示如下的页面,里面的其他文件都看不到. 解决办法:(不知道是具体的什么原因引起的) 1. 关闭IDEA, 2.然后删除项目文件夹下的. ...

  3. [Leetcode Week2]Sort Colors

    Sort Colors题解 原创文章,拒绝转载 题目来源:https://leetcode.com/problems/sort-colors/description/ Description Give ...

  4. Kuangbin 带你飞专题十一 网络流题解 及模版 及上下界网络流等问题

    首先是几份模版 最大流:虽然EK很慢但是优势就是短.求最小割的时候可以根据增广时的a数组来判断哪些边是割边.然而SAP的最大流版我只会套版,并不知道该如何找到这个割边.在尝试的时候发现了一些问题.所以 ...

  5. K-D树问题 HDU 4347

    K-D树可以看看这个博客写的真心不错!这里存个版 http://blog.csdn.net/zhjchengfeng5/article/details/7855241 HDU 4349 #includ ...

  6. Makefile之大型工程项目子目录Makefile的一种通用写法【转】

    转自:http://www.cnblogs.com/skyofbitbit/p/3680753.html 管理Linux环境下的C/C++大型项目,如果有一个智能的Build System会起到事半功 ...

  7. WEB字体,多列布局和伸缩盒

    WEB字体 语法 @font-face{ font-family:""; src:url() format() ... } 兼容性写法 @font-face { font-fami ...

  8. jQuery点击自身以外地方关闭弹出层

    转载自:http://blog.163.com/abkiss@126/blog/static/325941002012111754349590/ 主要功能是点击显示,然后通过点击页面的任意位置都能关闭 ...

  9. Spring+Junit,测试事务时,一直回滚

    研究了好长时间,都不知道原因,也不能解决. 控制台又没有报异常,但是就是一直回滚.注释掉spring声明式配置的代码,就能正确的更新数据. 从网上看了,别人的文章 http://blog.csdn.n ...

  10. ros中删除某个包之后用apt安装的包找不到

    原因是工作空间devel里还存有原来的二进制可执行文件,将build和devel内容全删除后再catkin_make就好了