发布了一个高性能的format实现
许多JS工具库或者框架都提供了字符串格式化的方法,如Atlas,典型代码如:
String.format('Hello {0}!', 'world') 返回 "Hello world!"
但是没有一个有像这个实现 http://blog.csdn.net/hax/archive/2006/11/27/1416692.aspx 那样好的性能,特别是在有大量占位符时性能不会快速衰退。观察其实现代码,每次format调用所作的只是一次Array.join然后一次String.replace(regex, string)的操作,两者都是js中的native方法,而不会有任何自定义函数调用。
用法:
1. String.format('Hello $1!', 'world') 或 'Hello $1!'.format('world')
2. 如果要包含$字符,需写成$$,如 '$$version $1$$'.format('1.0') 返回$version 1.0$
3. 字符串内不能包含字符0x1f(ASCII和Unicode中所谓数据分隔符,实际中几乎不会使用,可能只有一些很古老的自定义数据文件格式会用到)
好的想法要给大家共享,所以发布出来,也供高手参详。
注意,代码以GPL/LGPL的许可证发布,通常可自由使用。如需以其他方式使用,需获得作者我的同意。
问题点数:200、回复次数:68Top
1 楼myvicy(我来也!)回复于 2006-11-27 14:23:02 得分 9
顶就一个字。Top
2 楼zs178(zh-cn)回复于 2006-11-27 14:41:16 得分 5
嘿嘿,楼主好人啊,撒200分
顶了~~~~~~~Top
3 楼bigman_lfj(盐水小鱼)回复于 2006-11-27 14:50:43 得分 5
赫赫,顶一下Top
4 楼woneinwy(★★★★★★★★★★@しǒひê)回复于 2006-11-27 14:55:07 得分 5
接分不留名Top
5 楼mh_rock(Rock 努力学习C#)回复于 2006-11-27 15:03:51 得分 5
顶一下,接分Top
6 楼CutBug(.NetZergling)回复于 2006-11-27 15:06:05 得分 5
JFTop
7 楼chenguang79(小虫)回复于 2006-11-27 15:06:35 得分 4
感谢楼主共享Top
8 楼ttyp(@http://www.cnblogs.com/ttyp/)回复于 2006-11-27 15:24:41 得分 10
是不错,但是对你发布的GPL不是很欣赏,为什么不是BSD,如果需要你的同意,我宁愿使用自己编写的,尽管慢点,呵呵Top
9 楼hbhbhbhbhb1021(天外水火(我要多努力))回复于 2006-11-27 15:27:22 得分 10
hax (海曦)兄弟,你博客上写的比较乱,怕是很多人都不会去仔细研究,第一眼看上去我也是没看明白,把你的整理成了可以看到结果的例子,大家一起研究看看
<script language=javascript>
if (!String._FORMAT_SEPARATOR){
String._FORMAT_SEPARATOR = String.fromCharCode(0x1f);
String._FORMAT_ARGS_PATTERN = new RegExp('^[^' + String._FORMAT_SEPARATOR + ']*' + new Array(100).join('(?:.([^' + String._FORMAT_SEPARATOR + ']*))?'));
}
if (!String.format)
String.format = function (s){
return Array.prototype.join.call(arguments, String._FORMAT_SEPARATOR).replace(String._FORMAT_ARGS_PATTERN, s);
}
if (!''.format)
String.prototype.format = function (){
return (String._FORMAT_SEPARATOR +Array.prototype.join.call(arguments, String._FORMAT_SEPARATOR)).replace(String._FORMAT_ARGS_PATTERN, this);
}
var name = 'world';
var result = 'Hello $1!'.format(name);
alert(result)
var letters = String.format('$1$2$3$4$5$6$7$8$9$10$11$12$13$14$15$16$17$18$19$20$21$22$23$24$25$26', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z');
alert(letters)
</script>Top
10 楼descreekert(descreekert)回复于 2006-11-27 15:37:30 得分 3
收藏,学习Top
11 楼hbhbhbhbhb1021(天外水火(我要多努力))回复于 2006-11-27 15:38:34 得分 10
这样不好吗?为什么占位符编号到几,就要几次,高版本的浏览器replace函数支持的,hax (海曦)兄弟你的正则预查同样需要高版本的浏览器。
var temp="'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'".replace(/[\' ]/g,'').split(",")
var i=0;
letters='$1$2$3$4$5$6$7$8$9$10$11$12$13$14$15$16$17$18$19$20$21$22$23$24$25$26'.replace(/\$\d{1,2}/g,function(a){return temp[i++]})
alert(letters)Top
12 楼bejon(阿牛[如果我懂,必坦诚相告;如果您懂,请不吝赐教。])回复于 2006-11-27 15:42:39 得分 3
收藏,学习Top
13 楼ttyp(@http://www.cnblogs.com/ttyp/)回复于 2006-11-27 15:45:29 得分 10
hbhbhbhbhb1021(天外水火(我要多努力))
你用function(a){return temp[i++]})还是需要横多次替换啊Top
14 楼hax(海曦)回复于 2006-11-27 15:46:15 得分 0
To ttyp:
我并不排斥revised BSD,且revised BSD与GPL是兼容的。使用GPL/LGPL,只是因为我更欣赏GPL/LGPL推广Free Software的理念,且这小段代码是从我的PIES项目中攫取,该项目采用GPL/LGPL许可证。
LGPL还是很宽松的,一般而言你不必获得我的许可,其实对于这样一小段脚本,我也没有考虑过怎样的用途是不合该许可证而需要得到我的同意的。这只是一小段代码而已,我只是随时传播自由的声明也。Top
15 楼hbhbhbhbhb1021(天外水火(我要多努力))回复于 2006-11-27 15:52:11 得分 10
to ttyp
我觉得应该和replace('$1','a').replace('$2','b')这种不同吧,至少匹配的时候不会一次全部匹配结束在重头匹配,就是说lastIndex属性不用移动那么多次,只走一遍Top
16 楼hax(海曦)回复于 2006-11-27 16:00:06 得分 0
To hbhbhbhbhb1021:
不清楚你在说哪个问题,我所指的是各种实现,包括不太好的实现。如果你是说高版本可以用自定义函数替换,而不需要调用多次replace,则ttyp已经回答你了 :)
至于浏览器版本问题,我在blog上已经写了,如jscript 5.5以下的(如ie 5.0默认所带jscript 5.0)确实不行。但现在还使用非ecmascript 3的js引擎已经很稀少了,可忽略之。即使在某些商用环境中,不能升级浏览器如ie 5.0,至少也可只升级脚本引擎的。Top
17 楼ttyp(@http://www.cnblogs.com/ttyp/)回复于 2006-11-27 16:00:47 得分 10
TO hax:
LGPL是可以转换为商业代码的,有赚取广大free software思想之嫌疑,相对的BSD,appache似乎自由度更大一点,还有个啥协议,只要使用者申明作者的就能使用,忘记名字了。
TO hbhbhbhbhb1021(天外水火(我要多努力)) :
是不同,但是用了function,至少会产生很多临时变量和堆栈吧Top
18 楼hax(海曦)回复于 2006-11-27 16:08:53 得分 0
To (hb){5}1021 (名字太长,我用正则来写,呵呵):
性能下降的关键在于自定义函数还是要被调用n次,例如"$1 $1 $1 $1".replace(/[$][0-9]/, f),f还是被调用了4次。而且随占位符的增加至少是线形增长。
而我所写的实现始终只有一次Array.join和String.replace,且用到正则的复杂度是恒定的,因此整体性能是常数的。Top
19 楼Go_Rush(我的技术博客http://ashun.cnblogs.com/)回复于 2006-11-27 16:45:08 得分 2
支持一下。楼主 JavaScript功底确实很厉害。
我是看晕了Top
20 楼galant2008(無賴)回复于 2006-11-27 16:58:34 得分 2
学习一下Top
21 楼jiangtao088(不够专业)回复于 2006-11-27 17:09:27 得分 2
markTop
22 楼hbhbhbhbhb1021(天外水火(我要多努力))回复于 2006-11-27 17:28:54 得分 2
的确很经典,:)Top
23 楼mingxuan3000(铭轩)回复于 2006-11-27 18:27:51 得分 2
学习Top
24 楼hax(海曦)回复于 2006-11-27 18:30:15 得分 0
经典不敢。只是抛砖引玉一下,如何在螺丝壳里做道场,其要义就是充分利用螺丝壳。
这个代码片段其实是我在写logging的时候的产物,下一次我会把整个log4js拿出来与大家探讨,如何避免log对性能的影响。Top
25 楼ttyp(@http://www.cnblogs.com/ttyp/)回复于 2006-11-27 18:33:35 得分 2
非常期待log4jsTop
26 楼hbhbhbhbhb1021(天外水火(我要多努力))回复于 2006-11-27 19:45:23 得分 2
是哦,效率一般都出在IO上,前几天我就遇到了这个问题,日志打太多了,速度慢。Top
27 楼btbtd(签名加载中...请稍候...单击...双击ok)回复于 2006-11-27 20:39:43 得分 2
直接进行二进制操作才见效率,,JS就算了吧.Top
28 楼Love_My()回复于 2006-11-27 20:52:21 得分 2
.... 直接接分Top
29 楼precipitant(塞北的雪)回复于 2006-11-28 08:14:57 得分 2
先标记,有空研究。Top
30 楼myminimouse(坚决不用baidu)回复于 2006-11-28 08:24:02 得分 2
看看Top
31 楼royeleo(煨灶猫||(只要一颗★))回复于 2006-11-28 09:46:39 得分 2
赫赫,顶一下Top
32 楼mldswt(一个普通老百姓的要求:农妇,果园,有点田。)回复于 2006-11-28 10:36:35 得分 2
学习中Top
33 楼qiuyi21()回复于 2006-11-28 11:52:08 得分 2
很好Top
34 楼microjunjun()回复于 2006-11-28 14:19:22 得分 2
formatTop
35 楼yousite1(国雾)回复于 2006-11-28 15:29:24 得分 2
经典,楼主谢谢Top
36 楼huhh2004(冰石)回复于 2006-11-28 16:00:42 得分 2
mark
Top
37 楼fantiny(卖身不卖艺的菜鸟)回复于 2006-11-28 16:45:44 得分 2
占位看看Top
38 楼championmajian(小马||目前酒力:白的半斤,啤的3瓶)回复于 2006-11-28 17:14:50 得分 2
markTop
39 楼mb459()回复于 2006-11-28 17:57:08 得分 2
学习Top
40 楼ShinStone()回复于 2006-11-28 17:58:20 得分 2
好东西
Top
41 楼GavinLv(Gavin.Lv.)回复于 2006-11-28 19:49:35 得分 2
顶Top
42 楼handsomebird123(handsomebird123)回复于 2006-11-29 10:00:27 得分 2
markTop
43 楼zzzsea(兴,百姓苦。亡,百兴苦)回复于 2006-11-29 10:30:11 得分 2
扫分 MarkTop
44 楼brothercat(猫猫 ^_^)回复于 2006-11-29 10:39:39 得分 2
不说了撒,仰慕ing...
算了,我打算换版块了,非技术讨论版怎么样?^_^Top
45 楼w78z007()回复于 2006-11-29 10:47:39 得分 2
为什么要换啊,我们这些后辈还要您的支持呢Top
46 楼liuph3000()回复于 2006-11-29 10:53:08 得分 2
markTop
47 楼daluoboequalto(大萝卜)回复于 2006-11-29 11:48:10 得分 2
是好东西,
螺丝壳里做道场。Top
48 楼xuancaoer(当回复为'mark'的时候请别给我分)回复于 2006-11-29 12:31:58 得分 2
markTop
49 楼gzty(【风逍遥】123笨小孩天天快乐)回复于 2006-11-29 13:05:44 得分 2
是好东西,
螺丝壳里做道场
==========================
什么意思啊
看不懂`:(Top
50 楼championmajian(小马||目前酒力:白的半斤,啤的3瓶)回复于 2006-11-29 13:14:13 得分 2
markTop
51 楼bamboo_2001(千棵竹)回复于 2006-11-29 15:49:57 得分 2
okTop
52 楼zoloao()回复于 2006-11-29 16:20:44 得分 2
是好东西,
螺丝壳里做道场
==========================
什么意思啊
看不懂`:(
==========================
小题大做啊
Top
53 楼afoskoo(暂停打印)回复于 2006-11-29 17:16:26 得分 2
看不懂到底format个啥。
String.format('Hello {0}!', 'world') 返回 "Hello world!" 这有什么意思啊?
楼主发两个有价值的例子看看啊。Top
54 楼li1229363()回复于 2006-11-29 17:42:05 得分 2
接分+标记~LZ大方!Top
55 楼muxrwc(厕所宣言:信念永不变,追猫永不弃。)回复于 2006-11-29 17:52:35 得分 2
轻轻的UP小下,然后在悄悄的离开。。Top
56 楼okitgo(IT浪涛儿)回复于 2006-11-29 19:13:11 得分 2
upTop
57 楼nanfeng916()回复于 2006-11-29 21:29:48 得分 2
顶起来,Top
58 楼emilchan6k(emilchan)回复于 2006-11-29 22:00:53 得分 2
jf,markTop
59 楼woyingjie(Hobo)回复于 2006-11-30 09:09:16 得分 10
var arr = new Array();
var a = new Date();
for (var i=0; i<10000; i++)
{
arr.join(String.format("$1,$2,$3$4", "a", "b", "c", "d"));
}
alert(new Date() - a); //705毫秒
var b = new Date();
for (i=0; i<10000; i++)
{
arr.join("a" + "," + "b" + "," + "c" + "d");
}
alert(new Date() - b); //344毫秒Top
60 楼squallqiu(刮风还下雨)回复于 2006-11-30 09:11:47 得分 2
不错。仔细看看。Top
61 楼hax(海曦)回复于 2006-11-30 09:12:54 得分 0
楼上的,用字符串连接当然最快,format是为了提高代码可读性,在此前提下尽量提速。Top
62 楼hax(海曦)回复于 2006-11-30 13:08:37 得分 0
补充一下,今天看到有人问要在第一个参数后跟一个1怎么办,因为不能写成 '$11'.format('a')。
这个其实很简单,写成'$011'.format('a')即可,返回结果为'a1'。Top
63 楼shjohnson()回复于 2006-11-30 13:11:36 得分 2
顶你个肺Top
64 楼FEB15(张郎)回复于 2006-11-30 13:16:22 得分 2
markTop
65 楼qqulijun(探讨中国软件)回复于 2006-11-30 13:52:10 得分 2
感谢楼主Top
66 楼wuyan_xjb()回复于 2006-12-07 17:16:07 得分 0
log4js ? 好像早就有了吧?Top
67 楼meizz(梅花雪)回复于 2006-12-16 17:44:51 得分 0
'$1$2$3$4$5$6$7$8$9$10'.format('a');
这样的替换,应该的结果是 a$2$3$4$5$6$7$8$9$10
而你给的结果却只是一个字母 a ,好象不太对吧!Top
68 楼meizz(梅花雪)回复于 2006-12-16 18:18:52 得分 0
与你这样不正确且要求颇多的方法相比,我情愿要一个效率差些,但是正确,且兼容低版本浏览器的方法:
String.prototype.format = function(str)
{
if(arguments.length==0) return this;
try
{
var A = arguments;
return this.replace(/\{(\d+)\}/g, function(a, b){return A[b]||a});
}
catch (ex)
{
for(var i=0, s=this, n=arguments.length; i<n; i++)
{
s = s.split("{"+ i +"}").join(arguments[i]);
}
}
return s;
}Top





