神级程序员JavaScript300行代码搞定汉字转拼音


Posted in Javascript onMay 20, 2017

一.汉字转拼音的现状

首先应该说,汉字转拼音是个强需求,比如联系人按拼音字母排序/筛选;比如目的地(典型如机票购买)
按拼音首字母分类等等。但是这个需求的解决方案,但好像没听过什么巧妙的实现(特别是浏览器端),大概都需要一个庞大的字典。
具体到JavaScript,查查github和npm,比较优秀的处理汉字转拼音的库有pinyin
和pinyinjs,可以看到,两者都自带了庞大的字典。
这些字典动辄几十上百KB(有的甚至几MB),想在浏览器端使用还是需要一些勇气的。所以当我们碰到汉字转拼音的需求,也不怪我们第一反应就是拒绝需求(或者服务端实现)。
现在,如果我告诉你可以浏览器端300行代码实现汉字转拼音,是不是不可置信?

二.从安卓4.2.2联系人代码说起

再次强调这篇博客——利用Android源码,轻松实现汉字转拼音功能。
今天和大家分享一个从Android系统源代码提取出来的汉字转成拼音实现方案,只要一个类,560多行代码就可以让你轻松实现汉字转成拼音的功能,且无需其他任何第三方依赖。
是不是打破了你的思维定势:难道有什么强大的算法可以抛弃字典?
第一遍看完博客,稍有些失望,并没有什么算法解析,只是介绍了从安卓代码发现的这几百行代码。第二遍时带着移植到JavaScript的想法阅读代码,算是弄懂了原理,于是开始了踩坑的移植之旅。

三.手把手教你300行JavaScript代码实现汉字转拼音

首先直指核心:为什么有汉字转拼音必须有庞大字典的思维定势?
因为汉字的排布和拼音并有什么关联,比如在汉字区间\u4E00-\u9FFF,前一个可能是ha,后一个可能就是ze,没有办法从汉字的unicode关联到拼音,所以只能有一个庞大的字典记录每个汉字(或常用汉字)的拼音。
但是,假设我们可以把所有汉字按拼音排序,比如按'A','AI','AN','ANG','AO','BA',...,'ZUI','ZUN','ZUO'排序,那么,我们只需要记住每个相同拼音的汉字队列的第一个汉字就好了。那么,所需要的字典就会很小(覆盖所有拼音即可,拼音数量本身不多)。
现在,难点就是把汉字按拼音排序了。很幸运,ICU/本地化相关的API提供了这个排序API(如果没有方便的排序/比较方法,那么本篇文章可能就不会出现了)。

所以,这就是为什么300行可以实现汉字转拼音:Intl.CollatorAPI:Intl.Collator内部实现了本土化相关的字符串排序。我们通过Intl.Collator.prototype.compare可以把所有汉字基本按照拼音来排序。
边界汉字表:记录了排序的边界点。该汉字表的每个汉字都是排序后相同拼音的汉字集合的首个汉字(Eachunihansisthefirstonewithinsamepinyinwhencollatoriszh_CN)。
说到这里,可能仍然有没说清楚的地方,所以直接上一段代码:

 神级程序员JavaScript300行代码搞定汉字转拼音

神级程序员JavaScript300行代码搞定汉字转拼音

有兴趣的同学可以执行node--icu-data-dir=node_modules/full-icu上面的脚本.js看看,然后看看是不是得到了基本按照拼音排序的汉字表。

这里有几点要注意:

我再次加粗了“基本”,因为我们得到的汉字列表并没有完全按照拼音来排序,中间偶尔有一些其它拼音的汉字插入,这点在制作边界表时要额外注意。
上面脚本里得出的表是所有汉字的排序,其中有些和安卓代码里HanziToPinyin.java的表有不同,所以需要更新HanziToPinyin.java的表。(从Java转到JavaScript的最大的坑和工作量:更正边界表)
相信大家都看到了核心代码:constCOLLATOR=newIntl.Collator(['zh-Hans-CN']),Intl.Collator
(这里指定locale是中国zh-Hans-CN)正是能把汉字按拼音排序的关键,它是按locale-specific顺序,排序字符串的InternationalizationAPI。
执行脚本时请先npmifull-icu,这个依赖会自动安装缺失的中文支持并提示如何指定ICU数据文件来执行脚本。
1.ICUICU即InternationalComponentsforUnicode,为应用提供Unicode和国际化支持。
ICUisamature,widelyusedsetofC/C++andJavalibrariesprovidingUnicodeandGlobalizationsupportforsoftwareapplications.ICUiswidelyportableandgivesapplicationsthesameresultsonallplatformsandbetweenC/C++andJavasoftware.
并且ICU提供了本地化字符串比较服务(UnicodeCollationAlgorithm+本地特定的比较规则):
Collation:Comparestringsaccordingtotheconventionsandstandardsofaparticularlanguage,regionorcountry.ICU'scollationisbasedontheUnicodeCollationAlgorithmpluslocale-specificcomparisonrulesfromtheCommonLocaleDataRepository,acomprehensivesourceforthistypeofdata.
在现代浏览器上,一般ICU内置了对用户本地语言的支持,我们直接使用即可。
但对node.js来说,通常情况下,ICU只包含了一个子集(通常是英语),所以我们需要自行添加对中文的支持。一般来说,可以通过npminstallfull-icu安装full-icu
来安装缺失的中文支持。(参见上面node--icu-data-dir=node_modules/full-icu)。
2.IntlAPI上一小节应该基本讲清楚了国际化/本地化相关的知识,这里再补充一下内置API的使用。怎么查看用户语言和Runtime是否支持这个语言?Intl.Collator.supportedLocalesOf(array|string)
返回包含支持(不用回退到默认locale)的locales的数组,参数可以是数组或字符串,为想要测试的locales(即BCP47languagetag)。

神级程序员JavaScript300行代码搞定汉字转拼音

构造Collator对象和排序字符串

神级程序员JavaScript300行代码搞定汉字转拼音

通过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',...
,这正是我们上面提到的汉字转拼音的关键。

四.边界表更正

神级程序员JavaScript300行代码搞定汉字转拼音

 显然,这个边界表是有问题的,需要更正。
我们可看到,大部分的汉字被转成了qing,可见,qing这个拼音对应的汉字有问题。
找到这个汉字,是'\u72c5'/'??,加上前后各一个字,['\u4eb2','\u72c5','\u828e']/["亲","??,"芎"]

搜索,'\u72c5'/'??可以读qing,但现在多读kuang,这应该就是错误的原因了。
根据最初得到那张所有汉字的排序表,qing的第一个汉字是'\u9751'/'?'。
改动后,转换失败的只剩104了。

 神级程序员JavaScript300行代码搞定汉字转拼音

Javascript 相关文章推荐
dropdownlist之间的互相联动实现(显示与隐藏)
Nov 24 Javascript
javascript与asp.net(c#)互相调用方法
Dec 13 Javascript
JavaScript获取路径设计源码
May 22 Javascript
JS中处理时间之setUTCMinutes()方法的使用
Jun 12 Javascript
JS实现仿Windows7风格的网页右键菜单效果代码
Sep 11 Javascript
深入学习jQuery Validate表单验证(二)
Jan 18 Javascript
Zero Clipboard实现浏览器复制到剪贴板的方法(多个复制按钮)
Mar 24 Javascript
JavaScript编写带旋转+线条干扰的验证码脚本实例
May 30 Javascript
javascript显示倒计时控制按钮的简单实现
Jun 07 Javascript
如何利用模板将HTML从JavaScript中抽离
Oct 08 Javascript
基于JavaScript实现图片连播和联级菜单实例代码
Jul 28 Javascript
Vue项目实现简单的权限控制管理功能
Jul 17 Javascript
在使用JSON格式处理数据时应该注意的问题小结
May 20 #Javascript
微信小程序利用co处理异步流程的方法教程
May 20 #Javascript
关于jQuery库冲突的完美解决办法
May 20 #jQuery
layui文件上传实现代码
May 20 #Javascript
为你的微信小程序体积瘦身详解
May 20 #Javascript
jquery.guide.js新版上线操作向导镂空提示jQuery插件(推荐)
May 20 #jQuery
使用node.js搭建服务器
May 20 #Javascript
You might like
Apache 配置详解(最好的APACHE配置教程)
2010/07/04 PHP
ThinkPHP使用心得分享-分页类Page的用法
2014/05/15 PHP
php中print(),print_r(),echo()的区别详解
2014/12/01 PHP
php实现图片上传时添加文字和图片水印技巧
2020/04/18 PHP
PHP实现阿里大鱼短信验证的实例代码
2017/07/10 PHP
CI(CodeIgniter)框架中URL特殊字符处理与SQL注入隐患分析
2019/02/28 PHP
Extjs中DisplayField的日期或者数字格式化扩展
2010/09/03 Javascript
javascript仿qq界面的折叠菜单实现代码
2012/12/12 Javascript
js的hasownproperty使用示例
2014/03/02 Javascript
AngularJS的内置过滤器详解
2015/05/14 Javascript
JavaScript中使用指数方法Math.exp()的简介
2015/06/15 Javascript
JS实现隐藏同级元素后只显示JS文件内容的方法
2016/09/04 Javascript
将form表单通过ajax实现无刷新提交的简单实例
2016/10/12 Javascript
微信小程序开发一键登录 获取session_key和openid实例
2016/11/23 Javascript
搭建一个nodejs脚手架的方法步骤
2019/06/28 NodeJs
Django中实现点击图片链接强制直接下载的方法
2015/05/14 Python
python3.5使用tkinter制作记事本
2016/06/20 Python
Python面向对象编程中关于类和方法的学习笔记
2016/06/30 Python
Python基于回溯法子集树模板解决0-1背包问题实例
2017/09/02 Python
Django之Mode的外键自关联和引用未定义的Model方法
2018/12/15 Python
Python查找最长不包含重复字符的子字符串算法示例
2019/02/13 Python
django框架中ajax的使用及避开CSRF 验证的方式详解
2019/12/11 Python
ansible动态Inventory主机清单配置遇到的坑
2020/01/19 Python
浅谈Pytorch torch.optim优化器个性化的使用
2020/02/20 Python
美国演唱会和体育门票购买网站:Ticketnetwork
2018/10/19 全球购物
六一儿童节活动策划方案
2014/01/27 职场文书
运输服务质量承诺书
2014/03/27 职场文书
项目合作意向书范本
2014/04/01 职场文书
机关党员三严三实心得体会
2014/10/13 职场文书
数学教师求职信范文
2015/03/20 职场文书
朋友聚会开场白
2015/06/01 职场文书
《圆明园的毁灭》教学反思
2016/02/16 职场文书
django注册用邮箱发送验证码的实现
2021/04/18 Python
一文搞懂Golang 时间和日期相关函数
2021/12/06 Golang
Vue监视数据的原理详解
2022/02/24 Vue.js
JS class语法糖的深入剖析
2022/07/07 Javascript