/pinyin

汉字转拼音,支持20870个汉字,包含完整的多音字

Primary LanguageJavaScriptMIT LicenseMIT

npm tag License download

汉字转拼音

支持20870个汉字,包含完整的多音字,无第三方依赖,压缩前仅72KB。

常用汉字区间为\u4e00-\u9fa5,共20902个汉字,该库只支持20870个汉字的拼音,未收录的汉字是:"乥乲兙兛兝兞兡兣兺匁厼叾哛唜唟喸嗧囕夞巼怾旕朩朰栍桛椧烪猠瓧瓩瓰瓱瓲瓼甅硛硳穒縇莻虄襨迲闏鞥龥"

安装

npm i --save jian-pinyin

使用示例

import Pinyin from 'jian-pinyin'
console.log(Pinyin.getSpell('阿里巴巴欢迎您'));//[e,a],li,ba,ba,huan,ying,nin

因为“阿”是多音字,因此结果是 [e,a],li...这样子的,当您需要遇到多音字自已处理时,可以这样:

import Pinyin from 'jian-pinyin'
Pinyin.getSpell('阿里巴巴欢迎您',function(charactor,spell){
    console.log(charactor,spell);
    return spell[1];
});

当获取词语或者名字的拼音时,多个拼音使用英文逗号来连接,也可以自定义连接多个拼音的连接字符,例如要将拼音直接拼接,不加入特殊字符传入 '' 为第三个参数:

import { getSpell } from 'jian-pinyin'
getSpell('阿里巴巴欢迎您',function(charactor,spell){
    console.log(charactor,spell);
    return spell[1];
}, '');

如果浏览器支持localeCompare

只有部分浏览器支持中文按拼音排序,如果浏览器支持则可以使用Pinyin.lcTranslate()来获取拼音

压缩说明

网上常见的方案的都是字典表的思路,把所有汉字的拼音罗列一遍,我也是这样的思路。因为要达到能处理20870个汉字,同时要保障网络传输,本人想办法写了一个压缩算法,目前这个版本是压缩好的,带自解压功能,仅60-70kb,远远小于网上的其它方案的实现。

以下说明压缩思路:

汉字转拼音,最理想状态下是使用Stirng.prototype.localCompare了,把汉字按拼音排序,然后再查找汉字位于哪个区间,这种实现方案的代码量是最少的,但是由于这玩意并不是所有浏览器实现都一样,例如chrome早期的就不是按拼音排序,所以这个方案先放一边

那网上最常见的就是码表了,比如{"a":"吖阿啊..."},这种形式的最可靠稳定,但唯一不足的是码表太大,汉字的范围最常用的在 \u4e00-\u9fa5 这个区间里,其它区间的暂不考虑。这个区间有20928个汉字(后来经我资料查找,发现这个区间里有些汉字并没有对应的拼音,也有些汉字无法正常显示,所以被我精简到了20870个汉字了,当然网上也有只把常用的几千个汉字做为码表的)。

现在的问题就来了,如果把这2w多个汉字做为码表存在js文件里无异是非常大的,我们需要想办法压缩,而在压缩前我们还有些问题需要解决:

如果存放js代码的文件用utf-8来保存,那如果这个js被放在了gbk编码的页面上,并且script标签未指定charset utf-8,那么这个js中的汉字是会乱码的,所以需要编码,常用的是unicode成{"a":"\u5416\u963f\u554a..."},这样就不会有问题了。

如果用unicode编码,则2w多个汉字大概需要12w个字符表示(一个汉字6个字符)。这个量是非常大的,如何用最少的字符来表示这些汉字成了压缩的关键

我们知道每个汉字都可以用charCodeAt取到相应的数字编码,也可以用String.fromCharCode进行还原,例如:"我".charCodeAt(0);//20105;我们也可以用String.fromCharCode(20105)还原成"我"字,OK,到这一步,最小汉字是19968;最大是40896。如果把所有汉字用数字表示,则只需要10w个字符即可,1个汉字对应5个数字(当然,直接把这5位数字转16进制,则只需要4个就可以,2w多个汉字大约8w个字符,仍然很多)。

到这一步后,我给自已一个目标:能否用2个字符表示一个汉字?如果可以,那么大概只需要4w多字符就可以表示完,这个压缩比对10w个字符还是相当可喜的。

既然再压缩,那就把刚才的 汉字的数字 20105再进行压缩,这时候我采取的是进制转换,比如把它转成64进制等尽可能大的进制。如果转64进制,则2位64进制只能表示4096个汉字,这个太少了。我需要自已写一个大的进制转换,我把ascii码表重新拿出来,128个字符,除了不显示的,我挑中了从33到126之间的这些字符(除34,45,92三个外,因为我需要把程序发布到网上,别人可以复制粘贴之类的,所以需要可视字符),一共91个。那么91进制2位数可表示91*91=8281个,仍然不够。

回头再看汉字的区间,19968-40896 如果每个汉字都减去19968,则区间变成0-20928,如果把这个区间一分为2:0-10464 10465-20928,第二个区间每个汉字减去10465 则变成0-10463,至此2个区间各有1w个汉字,离我们的91进制2位表示的8281比较接近了。

假设我们用3个91进制的字符,则可以表示753571,表示2w个汉字绰绰有余,但这时候需要6w多个字符。如果我们使用91进制的2个字符,每个区间共有2000多个无法被表示,如果剩余的这2000多个用3个字符表示,我们会发现这2000多个的高位一样(xyz),都是'x';那么这时候大概需要4w加上2个6000,大概5w2k个字符即可表示完成。

当然,我们要对3位的高位给一个特殊的字符,这样我们再还原的时候就很方便还原了,这不是难事,忽略不讲

至此,我们就完成了压缩,最后的js大约共58kb