js优化篇——汉字转拼音...
时间:2010-08-15 来源:etherdream
网上类似的例子层出不穷,但大多万变不离其宗:把所有读音相同的字放在一行,这一行对应一个拼音;转换时搜索汉字所在的行,然后读取这行对应的拼音即可。且不说效率如何,单是记录下所有的汉字就是一个不小的空间。即使是常用的汉字就有近7000个,若是要包括“囧”这类的GBK汉字则超过20000,光是记录就有40 K之多。
显然这其中还有很大的改进空间。先琢磨下汉字的相关属性。GBK字库共有汉字20902个,而汉字的读音,即声母韵母的组合,不过400。平均读音相同50左右。假如能够得到从a-z按拼音顺序排列的所有汉字,那么每50个只需记录其第一个即可,就像关键帧一样可以导出其他所有。但汉字的Unicode并非是按读音排列的,所以必须得找个突破口。
回忆下String类的相关方法,与汉字的读音顺序有关。。。对了,String.localeCompare!你或多或少见过汉字排序的例子,此方法正是利用汉字的本地顺序对其排序。
而本地顺序正是拼音顺序!到这里,便是豁然开朗了。先罗列出所有的汉字(0x4e00-0x9fa5),然后再按本地顺序排序,即是所谓的字典顺序了。
var arr = []; for(var i=0x4e00; i<=0x9fa5; i++) arr[i-0x4e00] = i; arr = String.fromCharCode.apply(null, arr).split(""); arr.sort(function(a,b){return a.localeCompare(b)}); document.write(arr);
效果出现了,但效率却并不理想。跟踪下a.localeCompare(b)的次数,大约53万,虽不多,但IE却要运行上2秒的时间(双核2.5,IE6)。虽然此处只需运行一次而已,但仍然不是最理想的,仍需改进。
这里再提一次汉字的数量:2万多个,但实际的应用中用到的不过1/4而已。显然没有必要把所有的汉字都搬出来,倒不如运行时再根据每个汉字查询相应的拼音。二分法查询在此自然是能够大显身手了。
二分法大家都知道,每次取其半,然后再递归。。。虽然读音范围有400多,但只需8次判断就能够确定。唯一不同的就是判断的地方用localeCompare代替。对于转换过的汉字将其缓存,以后直接从缓存读取即可。
到此,大功告成。不过有点遗憾的是Chrome没有按照标准实现localeCompare。他们返回的居然是两者的Unicode之差。。。(无语)
演示(由于多音字生僻字的问题,其中诸多不标准的地方):
http://www.etherdream.com/funnyscript/Pinyin/Pinyin.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=gb2312" /> <title>GBK拼音</title> </head> <body> <mce:script type="text/javascript"><!-- var key = "吖哎安肮凹八挀扳邦勹陂奔伻皀边灬憋汃冫癶峬嚓偲参仓撡冊嵾噌叉犲辿伥抄车抻阷吃充抽出膗巛刅吹旾踔呲从凑粗汆镩蹿崔邨搓咑呆丹当刀恴揼灯仾嗲敁刁爹丁丟东吺剢耑叾吨多妸奀鞥仒发帆匚飞分丰覅仏垺夫旮侅干冈皋戈给根更工勾估瓜乖关光归丨呙妎咍兯夯茠诃黒拫亨乊叿齁乎花怀欢巟灰昏吙丌加戋江艽阶巾坕冂丩凥姢噘军咔开刊忼尻匼肎劥空廤扝夸蒯宽匡亏坤扩垃来兰啷捞仂雷塄唎俩嫾簗蹽咧厸伶溜咯龙娄噜驴孪掠抡捋嘸妈埋颟牤猫庅呅椚掹踎宀喵乜民名谬摸哞某母拏腉囡囔孬疒娞嫩莻妮拈娘鸟捏脌宁妞农羺奴女疟奻硸噢妑拍眅乓抛呸喷匉丕片剽氕姘乒钋剖仆七掐千呛悄切亲靑宆丘区峑炔夋亽呥穣荛惹人扔日戎厹嶿堧桵闰挼仨毢三桒掻色杀筛山伤弰奢申升尸収书刷衰闩双谁妁厶忪凁苏狻夊孙唆他囼坍汤仐忑膯剔天旫怗厅囲偷凸湍推吞乇屲歪乛尣危塭翁挝乌夕呷仙乡灱些忄兴凶休戌吅疶坃丫咽央幺倻膶一乚应哟佣优扜囦曰蒀帀災兂牂傮啫贼怎曽吒夈沾张佋蜇贞凧之中州朱抓拽专妆隹宒卓仔孖宗邹租劗厜尊昨".split(""); var pinyin = "AAiAnAngAoBaBaiBanBangBaoBeiBenBengBiBianBiaoBieBinBingBoBuCaCaiCanCangCaoCeCenCengChaChaiChanChangChaoCheChenChengChiChongChouChuChuaiChuanChuangChuiChunChuoCiCongCouCuCuanChuanCuanCuiCunCuoDaDaiDanDangDaoDeDenDengDiDiaDianDiaoDieDingDiuDongDouDuDuanDuiDunDuoEEnEngErFaFanFangFeiFenFengFiaoFoFouFuGaGaiGanGangGaoGeGeiGenGengGongGouGuGuaGuaiGuanGuangGuiGunGuoHaHaiHanHangHaoHeHeiHenHengHoHongHouHuHuaHuaiHuanHuangHuiHunHuoJiJiaJianJiangJiaoJieJinJingJiongJiuJuJuanJueJunKaKaiKanKangKaoKeKenKengKongKouKuKuaKuaiKuanKuangKuiKunKuoLaLaiLanLangLaoLeLeiLengLiLiaLianLiangLiaoLieLinLingLiuLoLongLouLuLvLuanLveLunLuoMMaMaiManMangMaoMeMeiMenMengMiMianMiaoMieMinMingMiuMoMouMeiMuNaNaiNanNangNaoNeNeiNenNNiNianNiangNiaoNieNinNingNiuNongNouNuNvNveNuanNuoOuPaPaiPanPangPaoPeiPenPengPiPianPiaoPiePinPingPoPouPuQiQiaQianQiangQiaoQieQinQingQiongQiuQuQuanQueQunRaRanRangRaoReRenRengRiRongRouRuRuanRuiRunRuoSaSaiSanSangSaoSeShaShaiShanShangShaoSheShenShengShiShouShuShuaShuaiShuanShuangShuiShuoSiSongSouSuSuanSuiSunSuoTaTaiTanTangTaoTeTengTiTianTiaoTieTingTongTouTuTuanTuiTunTuoWaWaiWanWangWeiWenWengWoWuXiXiaXianXiangXiaoXieXinXingXiongXiuXuXuanXueXunYaYanYangYaoYeYenYiYinYingYoYongYouYuYuanYueYunZaZaiZanZangZaoZeZeiZenZengZhaZhaiZhanZhangZhaoZheZhenZhengZhiZhongZhouZhuZhuaZhuaiZhuanZhuangZhuiZhunZhuoZaiZiZongZouZuZuanZuiZunZuo".split(/(?=[A-Z])/g); var cache = {}; var arrTree = []; /* * 函数: Cn2PinYin(w) * 注释: w为需转换成拼音的汉字 */ var Cn2PinYin; /* * 生成一颗条件分支的二叉树 */ function walk(a,b) { var c = Math.floor((a+b) / 2); if(c==b && b<a) //节点 { arrTree.push("r='", pinyin[c], "';"); return; } arrTree.push( //左分支 "if(w.localeCompare('", key[c], "')<0)"); walk(a, c-1); arrTree.push("else "); //右分支 walk(c+1, b); } /* * 初始化Cn2PinYin函数 * 对于转化过的汉字做缓存处理 */ function init() { arrTree.push("var r=cache[w];if(r)return r;"); //检查缓存 walk(0, key.length-1); //-递归生成源码 arrTree.push("return cache[w]=r;"); //-写入缓存 Cn2PinYin = new Function("w", arrTree.join("")); //编译 } init(); /* * 多个汉字连续转换,不是汉字则保留 */ function spell(content) { var fn = Cn2PinYin; var arr = []; var ch; for(var i=0,n=content.length; i<n; i++) { ch = content.charAt(i); arr[i] = (ch<"一" || ch>"龥")? //非汉字? ch:fn(ch); //保留:转换 } return arr.join(""); } /* * 测试 */ var $=function(v){return document.getElementById(v)}; function test() { $('pinyin').value=spell($('content').value); } // --></mce:script> <textarea id="content" cols="100" rows="10">大家好,这是一个汉字转拼音的小脚本!
汉字转拼音