今天在火车站转车,没零钱恰巧又渴了,到一家兼卖手机卡和零食饮料的小店要了瓶绿茶,居然要4块,不过物价局不管事也没办法,给了一张10块的让她找零。眼尖的MM拿着一大叠10块的说让我跟她换100块的整钱,没想那么多就同意了。
MM找回我9张10块的和6张1块的,我数了两遍说少了10块,之前绿茶的给了10块呢。MM不信,说要数一遍,是少了1张10块的,从旁边的mm那里拿了一张放在找回的钱上,递给我。这次我没有警觉,装进钱包赶公交车去了。MM还很热心的说不急,这里公交车10分钟一趟呢。
坐上公交车,我想去以前看过网友发过的帖,掏出钱包一数,果然少了2张10块的。
虽然以前看过别人的提醒帖,但是自己没有经历便少了许多警觉。记得当时MM数钱的手法,是把钱折向自己的(跟我折向前方不同),但是没注意(也没想过注意)她是怎么把钱卷走的。
好像以前在安阳火车站也有过类似的经历,但是当时并不知道鬼手,不知道钱是怎么没了的。
下午回来时经过火车站,赖在店里提醒其他顾客小心,终于把钱要了回来。p.s. 讨要的时候一定要注意他们的大汉,不要被他们围住了,尤其是人少的时候。
2009年3月10日星期二
2009年3月9日星期一
哎,这样的一个怪梦
凌晨梦见高中同学(六子)在学校里持枪挟持人质,我从屋里出去的的时候,不知哪里也随手弄了一支旧式长枪,提着去和六子谈判。六子不听劝,我便回了,到做校长的大爸家要手枪,说是救人质,不想一借就中。
装在裤兜里便走,后来不放心,问路人甲怎么拉上保险,居然是枪屁股逆时针旋转90度,这也太不保险啦。
换装在上衣口袋,想试试拉上保险是否会走火,砰的一声,上衣破了,摸摸从破洞里探出来的枪口,发现弹头还没离开弹壳,塞在枪口上。。。
这是个什么鬼梦。
装在裤兜里便走,后来不放心,问路人甲怎么拉上保险,居然是枪屁股逆时针旋转90度,这也太不保险啦。
换装在上衣口袋,想试试拉上保险是否会走火,砰的一声,上衣破了,摸摸从破洞里探出来的枪口,发现弹头还没离开弹壳,塞在枪口上。。。
这是个什么鬼梦。
2009年2月12日星期四
Gmail labs:Multiple inboxes
Gmail有了一个很棒的设计,多收件箱(Multiple inboxes),允许用户在收件箱里显示多个窗口,如标星邮件箱,草稿箱等,可以在选项中自行设置每个inbox的过滤条件,也可以选择不同的布局。
常用的条件有:
is:starred 标星邮件
is:unread 未读邮件
is:chat 聊天记录
is:draft 草稿邮件
另外可以使用标签过滤,如:
label:AD
发、收件地址
from:e@mail.address
to:e@mail.address
同样可以使用包含的关键字过滤:
%KEY_WORD%
总之,你可以使用Gmail的所有高级语法 。
2009年1月11日星期日
去除MSN 9的广告
今天发现msn 9可以用在Windows Server 2008上了,像我这么喜新厌旧的家伙,怎么会放过她,立马上。
客观的说,msn 9做的还是很棒的,已经能够支持群聊,界面也大有改善,不过它那个超级大而又吸引眼球的广告仍是那么讨厌,搜了一下,发现1个,2个...方法,各有优缺点,而又都没有去除干净:第1个只去除了主窗口(好友列表)下的大家伙,聊天窗口的广告没有被去除,而第2个方法功能比较饱满,但是不知道什么原因(可能是之前使用了第1中方法),开始的时候主窗口的广告反选第一个去广告选项可以去掉,后来无论正选反选都不行了,解决办法是先使用第2种方法,再使用第1种方法。
由于第2种方法的版本和最新的(14.0.8050.1202)有点不同,这里贴图如下:

客观的说,msn 9做的还是很棒的,已经能够支持群聊,界面也大有改善,不过它那个超级大而又吸引眼球的广告仍是那么讨厌,搜了一下,发现1个,2个...方法,各有优缺点,而又都没有去除干净:第1个只去除了主窗口(好友列表)下的大家伙,聊天窗口的广告没有被去除,而第2个方法功能比较饱满,但是不知道什么原因(可能是之前使用了第1中方法),开始的时候主窗口的广告反选第一个去广告选项可以去掉,后来无论正选反选都不行了,解决办法是先使用第2种方法,再使用第1种方法。
由于第2种方法的版本和最新的(14.0.8050.1202)有点不同,这里贴图如下:
这里有两个(第2个和第9个)去除广告的选项(Remove Advertisement),分别去除的是主窗口和聊天窗口的广告。点击左侧的选项,可以在右侧预览。

2009年1月6日星期二
Javascript无块级作用域
最近在做一系列Javascript压缩工具,语法压缩,语义压缩,字符串压缩均有涉及(p.s.有趣的是,压缩变量名之类的“有损压缩”不影响代码执行,但是字符串压缩这样的“无损压缩”却总是需要解压消耗)。
在实现压缩局部变量名时,最初的实现是将 if/else, for/in, do/while, switch/case/default, try/catch/finally, with和Object实例对象(后面统称为“块级作用域”)与function一样,都作为独立的作用域,但是测试发现在Javascript中并不是这么回事。
尝试着在块级作用域里声明定义变量:
虽然与某些编程规范不同,但是js就是这样了,唉。早知道这样,压缩变量名这部分也就不用那么费劲了,只得重写了。
另外还有一些Javascript作用域方面的文章:
Javascript中的作用域,好像是realazy翻译的,文章很好,虽然有点文不对题(主要阐述this的作用域链问题)。
js变量作用域及可访问性的探讨,详细介绍了各种变量的作用域及其可访问性问题,有部分不准确/正确的,出处未知,遍地都是转载。
附A 测试代码:
在实现压缩局部变量名时,最初的实现是将 if/else, for/in, do/while, switch/case/default, try/catch/finally, with和Object实例对象(后面统称为“块级作用域”)与function一样,都作为独立的作用域,但是测试发现在Javascript中并不是这么回事。
尝试着在块级作用域里声明定义变量:
if(true){会发现输出true,而且不论嵌套多深,也不论使用任何块级作用域进行嵌套,最后变量依然如同在调用处之前,而且同级的作用域中定义的一样;值为在此之前,在块级作用域中所做改变的结果。注意:如果块级作用域未被执行,则其中声明定义的变量会被声明(var name),但不被定义(即未被初始化,此时name为undefined,引用name时不抛异常)。
var bool=true;
}
document.write(bool); // output:true
if(false){var bool=true;}之前虽知道,IE里for(var i=0;...)里定义的i,在for之外也是可以使用的,但是现在才知道这种情况更为猖獗,大出我的意料之外,而更意外的是,IE 7(IE6?), Firefox 3(FF1,FF2?), Opera 9, Chrome 1, Safari 3表现均丝毫不差。
document.write(bool); // output:undefined
虽然与某些编程规范不同,但是js就是这样了,唉。早知道这样,压缩变量名这部分也就不用那么费劲了,只得重写了。
另外还有一些Javascript作用域方面的文章:
Javascript中的作用域,好像是realazy翻译的,文章很好,虽然有点文不对题(主要阐述this的作用域链问题)。
js变量作用域及可访问性的探讨,详细介绍了各种变量的作用域及其可访问性问题,有部分不准确/正确的,出处未知,遍地都是转载。
附A 测试代码:
// Global Scope附B 测试结果(IE 7, FF 3, Opera 9, Safari 3, Chorme 1均同):
if (true){
var v10 = true;
}else {
var v00 = false;
}
document.write("v10 : "+v10+"<br />");
document.write("v00 : "+v00+"<br />");
document.write("<hr />");
// Function Scope
function functionScopes(){
if (true){
// 以下均执行
var v11 = true;
do{
var v12 = true;
}while (false);
while (true){
var v13 = true;
break;
}
switch (1){
case 1:
var v14 = true;
default:
var v15 = true;
}
try{
var v16 = true;
throw new Error("");
}catch(e){
var v17 = true;
}finally{
var v18 = true;
}
for (var v19=0; v19<1; v19++){
var v1a=true;
}
with(v11){
var v1b = true;
}
function inn1(){
var inn11 = false;
}
}else {
// 以下均未执行
var v01 = false;
do{
var v02 = false;
}while (false);
while (false){
var v03 = false;
}
try{
var v06 = true;
throw new Error("");
}catch(e){
var v07 = true;
}finally{
var v08 = true;
}
switch (1){
case 1:
var v04 = true;
default:
var v05 = false;
}
for (var v09=0; v09<1; v09++){
var v0a=true;
}
with(v01){
var v0b = true;
}
function inn0(){
var inn01 = false;
}
}
document.write("v11 : "+v11+"<br />");
document.write("v12 : "+v12+"<br />");
document.write("v13 : "+v13+"<br />");
document.write("v14 : "+v14+"<br />");
document.write("v15 : "+v15+"<br />");
document.write("v16 : "+v16+"<br />");
document.write("v17 : "+v17+"<br />");
document.write("v18 : "+v18+"<br />");
document.write("v19 : "+v19+"<br />");
document.write("v1a : "+v1a+"<br />");
document.write("v1b : "+v1b+"<br />");
document.write("<hr />");
document.write("v01 : "+v01+"<br />");
document.write("v02 : "+v02+"<br />");
document.write("v03 : "+v03+"<br />");
document.write("v04 : "+v04+"<br />");
document.write("v05 : "+v05+"<br />");
document.write("v06 : "+v06+"<br />");
document.write("v07 : "+v07+"<br />");
document.write("v08 : "+v08+"<br />");
document.write("v09 : "+v09+"<br />");
document.write("v0a : "+v0a+"<br />");
document.write("v0b : "+v0b+"<br />");
document.write("<hr />");
try{alert(inn11);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(inn01);}catch(e){document.write((e.message||e)+"<br />");}
}
functionScopes();
document.write("<hr />");
try{alert(v11);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(v12);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(v13);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(v14);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(v15);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(v16);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(v17);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(v18);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(v19);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(v1a);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(v1b);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(v01);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(v02);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(v03);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(v04);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(v05);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(v06);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(v07);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(v08);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(v09);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(v0a);}catch(e){document.write((e.message||e)+"<br />");}
try{alert(v0b);}catch(e){document.write((e.message||e)+"<br />");}
v10 : true
v00 : undefined
v11 : true
v12 : true
v13 : true
v14 : true
v15 : true
v16 : true
v17 : true
v18 : true
v19 : 1
v1a : true
v1b : true
v01 : undefined
v02 : undefined
v03 : undefined
v04 : undefined
v05 : undefined
v06 : undefined
v07 : undefined
v08 : undefined
v09 : undefined
v0a : undefined
v0b : undefined
'inn11' 未定义
'inn01' 未定义
'v11' 未定义
'v12' 未定义
'v13' 未定义
'v14' 未定义
'v15' 未定义
'v16' 未定义
'v17' 未定义
'v18' 未定义
'v19' 未定义
'v1a' 未定义
'v1b' 未定义
'v01' 未定义
'v02' 未定义
'v03' 未定义
'v04' 未定义
'v05' 未定义
'v06' 未定义
'v07' 未定义
'v08' 未定义
'v09' 未定义
'v0a' 未定义
'v0b' 未定义
Labels:
Code,
Javascript
2009年1月2日星期五
开放篮球场地.地标工程
作为业余篮球爱好者,作为他乡游子,每到一个陌生的地方,都想尽快找到一个能施展球技、或者仅是活动一下筋骨的场地。就地解决当然也可以,但是如果有自由开放的美好世界,为什么不加入进去呢?
一般来说,大多数开放的篮球场地都在学校里(大学最多,中小学一般不对外开放),有一些公益场所也有简易的设施,所以希望能有一些学生朋友能给予帮助,我将尽力争取得到帮助。
基于这样的想法,我展开了一个“开放篮球场地.地标工程”的想法,为广大篮球爱好者服务。首先做好了几个我所知道的地标:http://labs.xianyun.org/OpenBasketballField/landmark/OpenBasketballField.All.in.One.kmz
将地址复制粘贴到Google Maps(谷歌地图)搜索栏,回车即可;或是下载到本地,使用Google Earth打开。
全国现有完整地标(All in One):
http://labs.xianyun.org/OpenBasketballField/landmark/OpenBasketballField.All.in.One.kmz
杭州:
http://labs.xianyun.org/OpenBasketballField/landmark/HangZhou.kmz
北京:
http://labs.xianyun.org/OpenBasketballField/landmark/BeiJing.kmz
另有在线地标,直接Google Maps上编辑即可(所有登录了Google账户的网友都可以编辑)
--
主要定位开放的篮球运动场地,默认为室外,尤其是免费的场地,室内或收费场地另附说明。
标题格式:地名[.开放封闭未知][.室外室内][.免费收费]
使用默认图标(期待志同之士提供更形象的图标)
红色不带圆点:
蓝色不带圆点:
紫色不带圆点:开放程度未知
红色带圆点:开放,人气旺
蓝色带圆点:开放,人气一般
紫色带圆点:
黄色不带圆点:封闭
以卫星地图为准。所有地标和文字描述仅作参考,欢迎修正(所有登录了Google帐号的朋友都可以进行修订)。
在线地标列表:
http://maps.google.com/maps/user?uid=108314985261981078822&hl=en
北京:
http://maps.google.com/maps/ms?hl=en&ie=UTF8&lr=lang_zh-CNlang_zh-TW&oe=UTF8&msa=0&msid=108623690175354072173.00045480d1fa17e9056ac
杭州:
http://maps.google.com/maps/ms?hl=en&ie=UTF8&lr=lang_zh-CNlang_zh-TW&oe=UTF8&msa=0&msid=108623690175354072173.00045f6778d694e0d3cc3
一般来说,大多数开放的篮球场地都在学校里(大学最多,中小学一般不对外开放),有一些公益场所也有简易的设施,所以希望能有一些学生朋友能给予帮助,我将尽力争取得到帮助。
基于这样的想法,我展开了一个“开放篮球场地.地标工程”的想法,为广大篮球爱好者服务。首先做好了几个我所知道的地标:http://labs.xianyun.org/OpenBasketballField/landmark/OpenBasketballField.All.in.One.kmz
将地址复制粘贴到Google Maps(谷歌地图)搜索栏,回车即可;或是下载到本地,使用Google Earth打开。
全国现有完整地标(All in One):
http://labs.xianyun.org/OpenBasketballField/landmark/OpenBasketballField.All.in.One.kmz
杭州:
http://labs.xianyun.org/OpenBasketballField/landmark/HangZhou.kmz
北京:
http://labs.xianyun.org/OpenBasketballField/landmark/BeiJing.kmz
另有在线地标,直接Google Maps上编辑即可(所有登录了Google账户的网友都可以编辑)
--
主要定位开放的篮球运动场地,默认为室外,尤其是免费的场地,室内或收费场地另附说明。
标题格式:地名[.开放封闭未知][.室外室内][.免费收费]
使用默认图标(期待志同之士提供更形象的图标)
红色不带圆点:
蓝色不带圆点:
紫色不带圆点:开放程度未知
红色带圆点:开放,人气旺
蓝色带圆点:开放,人气一般
紫色带圆点:
黄色不带圆点:封闭
以卫星地图为准。所有地标和文字描述仅作参考,欢迎修正(所有登录了Google帐号的朋友都可以进行修订)。
在线地标列表:
http://maps.google.com/maps/user?uid=108314985261981078822&hl=en
北京:
http://maps.google.com/maps/ms?hl=en&ie=UTF8&lr=lang_zh-CNlang_zh-TW&oe=UTF8&msa=0&msid=108623690175354072173.00045480d1fa17e9056ac
杭州:
http://maps.google.com/maps/ms?hl=en&ie=UTF8&lr=lang_zh-CNlang_zh-TW&oe=UTF8&msa=0&msid=108623690175354072173.00045f6778d694e0d3cc3
2008年12月30日星期二
Family Tree Builder 3.0发布
收到MyHeritage.com的邮件通知:Family Tree Builder 3.0发布了,比之前29种语言又新增了5种,纵然如此,亦纵然很久之前就有了MyHeritage中文站,但是软件的中文语言包还是迟迟未出。我之前为2.0版汉化的语言包仍然还可以凑合着用,注意:一些新版里添加的词条,默认显示为TODO。
其他功能没有细查,不知道有什么改善,虽然之前的中文乱码问题仍然存在(还没有中文语言包的情况下,这个可以理解,而且乱码部分不是太多),不过安装程序倒比2.0“大气”了些,而且默认选中将MyHeritage.com设为主页的选项,很智能的,另外还默认选中自动将族谱/家谱发布到网站的选项也很智能。
其他功能没有细查,不知道有什么改善,虽然之前的中文乱码问题仍然存在(还没有中文语言包的情况下,这个可以理解,而且乱码部分不是太多),不过安装程序倒比2.0“大气”了些,而且默认选中将MyHeritage.com设为主页的选项,很智能的,另外还默认选中自动将族谱/家谱发布到网站的选项也很智能。
Labels:
FamilyTreeBuilder
2008年12月29日星期一
Javascript String 方法效率大比拼
最初是通过梅子(梅花雪)关于大型字符串拼接效率(1,2)的研究得到启发,最近又看到never-online的从trim原型函数看js正则表达式的性能 ,里面有介绍正则表达式效率陷阱等问题,并提出解决方法。我向来对这些鸡毛蒜皮感兴趣,也开始对大型字符串各种方法实现的效率进行比较,并尝试提高这些方法的效率。
1. 大型字符串拼接
如梅子所言,使用数组的join方法确实是最好的实现,可以根据这个思路设计StringBuilder, StringBuffer类。
2. 大型字符串trim
其实never-online在他的文章里有一些说的不准确的地方,代码也不算很精炼。既然这是鸡毛蒜皮的小事,这些零碎东西当然要斤斤计较了。
我很久以前有收集到这样一些实现,I:
原以为String.replace方法比String.substr、String.substring效率低,于是想,只使用正则表达式获得两头(或者一头)的索引位置,然后使用substring方法取出子串,VI:
代码里老是for啊for的一大串,为了节省字节,而且有可能的话,也准备再优化一下循环,就实现了$indexOf和$lastIndexOf两个方法,可以传递一个返回boolean值的函数作为参数(本来还想也支持正则表达式参数的,想想以前扩展indexOf和lastIndexOf方法后的效率,就算了),这样就可以求得第一个非空白和最后一个非空白字符的位置了。
至于说要扩展到支持更长子串和起始索引,以后有需要再说了(顺便说一下,子串越长,有优化算法可以得到更高效率)。
另一个辅助方法:
说到这些实现的效率,无法一概而论,因为不同的字符串,它们的效率比也大不同,甚至异乎寻常。
影响trim方法效率的,主要与字符串的总长度,前面空白字符串长度,后面空白字符串长度,以及前中后的比例有关。详细的效率对比表有时间再上,这里只简要提一下:
对于较小的字符串,各种实现都有不错的表现,而对于大型字符串,则实现III, IV表现较为稳定,甚至可以处理超大型字符串(修正:之前有误写成I,II两个较为稳定)。
3. 大型字符串字节长度
即双字节长度为2。注意:这个提法其实也不正确,Javascript是使用Unicode字符集的,所有的字符都(有可能)是双字节字符。将汉字等转换为双字节长度主要是为了某些应用。
最土的方法还是循环遍历所有字符,I:
另一种实现则看起来很轻灵,寥寥几行,II:
bytes方法的效率:使用Javascript脚本循环大型字符串(I),确实远不如内置的replace方法(II)快,而使用正则表达式match方法(IV)又比replace方法(III)稍快,排名第二。
总结:
1. replace方法因匹配而被替换的子串愈长,效率愈低。
2. 根据目标字符串,选择合适的实现。
1. 大型字符串拼接
如梅子所言,使用数组的join方法确实是最好的实现,可以根据这个思路设计StringBuilder, StringBuffer类。
2. 大型字符串trim
其实never-online在他的文章里有一些说的不准确的地方,代码也不算很精炼。既然这是鸡毛蒜皮的小事,这些零碎东西当然要斤斤计较了。
我很久以前有收集到这样一些实现,I:
String.prototype.trim = function(){为了避免正则表达式使用括号带来的消耗,可以写成这样,II:
return this.replace(/(^\s+)(\s+$)/g, '');
};
String.prototype.trim = function(){另外有一套实现是这样的,III:
return this.replace(/(?:^\s+)(?:\s+$)/g, '');
};
String.prototype.lTrim = function(){其实调用函数也会多少有一点消耗,写成这样或许会快一点点(开个玩笑,这样写会带来一些冗余代码,这时候就需要基于效率(时间)、代码量(空间)和可维护性方面的考量了),IV:
return this.replace(/^\s+/, '');
};
String.prototype.rTrim = function(){
return this.replace(/\s+$/, '');
};
String.prototype.trim = function(){
return this.lTrim().rTrim();
};
String.prototype.trim = function(){后来我对正则表达式有了更多的了解,知道了贪婪与非贪婪匹配,于是自作聪明写了这一段:
return this.replace(/^\s+/, '').replace(/\s+$/, '');
};
String.prototype.trim = function(){我曾经为这段代码自鸣得意了好长一段时间,不过后来想到点号不包括换行符,字符串中间有换行符时,返回值就不正确了,于是不情愿的改成这样(多行模式效率也很低),V:
return this.replace(/^\s*(.*?)\s*$/, "$1"); // 两端空白字符贪婪匹配,中间字符非贪婪匹配。
};
String.prototype.trim = function(){谁知,这样的代码遇到大家伙时效率会一落千丈,哎,失败。
return this.replace(/^\s*((?:.\n)*?)\s*$/, "$1");
};
原以为String.replace方法比String.substr、String.substring效率低,于是想,只使用正则表达式获得两头(或者一头)的索引位置,然后使用substring方法取出子串,VI:
String.prototype.trim = function(){而最土的方法,莫过于两头都使用循环获得索引了,VII:
var l=this.length;
/^[\s]*/.test(this);
// /(?=[^\s])/.test(this);// -- never-online
var s = RegExp.lastIndex;
if(1==s && !Char.isBlank(this.charAt(0)))s=0;
if(s==l){return '';}
// /\s*$/.test(this);
// var e=RegExp.index;
var e=$lastIndexOf(function(c){return !Char.isBlank(c);});
e=-1==e?l:e+1;
return this.substring(s,e);
};
String.prototype.trim = function(){
var f=function(c){return !Char.isBlank(c);};
var l=this.length, s=this.$indexOf(f), e=this.$lastIndexOf(f);
if(-1==s)s=0;
e= -1==e?l:e+1;
return this.substring(s, e);
};
String.prototype.$indexOf = function(f){
for(var i=0,c,l=this.length; i=0; i--){
c=this.charAt(i);
if(f(c)){return i;}
}
return -1;
};
String.prototype.$lastIndexOf = function(f){
for(var i=this.length-1,c; i>=0; i--){
c=this.charAt(i);
if(f(c)){return i;}
}
return -1;
};
另一个辅助方法:
var Char = {到了永不在线(Google Translate翻译为“永远在线”)的算法,VIII:
isBlank:function(c){
//return /\s/.test(c);
return ' '==c '\t'==c '\r\n'==c '\n'==c '\r'==c;
}
};
String.prototype.trim = function(){最初这个算法让我很兴奋,直觉上,感觉这样效率肯定要高,不过事实并不是这么简单。
var s = this.replace(/^\s+/, '');
var l=s.length, e=l;
if(0==l){return '';}
for(var i=l-1; i>=0; i--){
if(!Char.isBlank(s.charAt(i))){
e=i+1;
break;
}
}
return this.substring(0,e);
};
说到这些实现的效率,无法一概而论,因为不同的字符串,它们的效率比也大不同,甚至异乎寻常。
影响trim方法效率的,主要与字符串的总长度,前面空白字符串长度,后面空白字符串长度,以及前中后的比例有关。详细的效率对比表有时间再上,这里只简要提一下:
对于较小的字符串,各种实现都有不错的表现,而对于大型字符串,则实现III, IV表现较为稳定,甚至可以处理超大型字符串(修正:之前有误写成I,II两个较为稳定)。
3. 大型字符串字节长度
即双字节长度为2。注意:这个提法其实也不正确,Javascript是使用Unicode字符集的,所有的字符都(有可能)是双字节字符。将汉字等转换为双字节长度主要是为了某些应用。
最土的方法还是循环遍历所有字符,I:
String.prototype.bytes = function(){这里判断字符是否双字节有很多方法,效率较高的之间相差(大概)不大。
var l=this.length, r=l, n=0xff;
for(var i=l; i>=0; i--){
if(this.charCodeAt(i)>n){
r++;
}
}
return r;
};
另一种实现则看起来很轻灵,寥寥几行,II:
String.prototype.bytes = function(){多动脑子,则想法愈多(也常把简单的事情复杂化),我想如果可以快速取得表达式(双字节/单字节)匹配次数,两值相加应该比较高效,III:
return this.replace(/[^\x00-\xff]/g,"xx").length;
};
String.prototype.bytes = function(){IV:
return this.length+this.replace(/[\x00-\xff]/g,"").length;
};
String.prototype.bytes = function(){另外看到梅花雪用数组能提供字符串拼接速度,也想:把字符串split为数组,不想对大型字符串而言,这split一步就慢得不行。
return this.length+(this.match(/[^\x00-\xff]/g)"").length;
};
bytes方法的效率:使用Javascript脚本循环大型字符串(I),确实远不如内置的replace方法(II)快,而使用正则表达式match方法(IV)又比replace方法(III)稍快,排名第二。
总结:
1. replace方法因匹配而被替换的子串愈长,效率愈低。
2. 根据目标字符串,选择合适的实现。
Labels:
Code,
Javascript
订阅:
博文 (Atom)


