鸟食轩

 Microsoft .NET[C#] MVP 2003
随笔 - 424, 文章 - 233, 评论 - 5417, 引用 - 344
数据加载中……

JScript实现的一个String.Format方法

    在.NET Framework的BCL类String中,有一个很有用的静态方法String.Format。当我们在输出一个需要由多个变量条目来组成的字符串时,非常的有用。特别是在对多语言支持时,使用Format方法来显示更加有价值。为了方便脚本编程,下面实现了一个JScript版的Format方法。

    BCL中的String.Format()是一个变参数的方法,第一个参数为格式化字符串,从第二个参数开始为格式化条目中的替换值。由于JavaScript天生就支持任意参数个数,所以可以很自然的实现一个非常sexy的Format方法。

    StringHelper.Format()方法源代码如下:
 // StringHelper.Format('{0}, {2}, {1}', 'abc', 'def', 'ghi');
 //
 return "abc, ghi, def".
 
StringHelper.Format = function(format)
 {
    
if ( arguments.length == 0 )
    {
        
return '';
    }
    
if ( arguments.length == 1 )
    {
        
return String(format);
    }

    
var strOutput = '';
    
for ( var i=0 ; i < format.length-2 ; )
    {
        
if ( format.charAt(i) == '{' && format.charAt(i+1!= '{' )
        {
            
var token = format.substr(i);
            
var index = String(token.match(/\d+/));
            
if ( format.charAt(i+index.length+1== '}' )
            {
                
var swapArg = arguments[Number(index)+1];
                
if ( swapArg )
                {
                    strOutput 
+= swapArg;
                }
                i 
+= index.length+2;
            }
        }
        
else
        {
            
if ( format.charAt(i) == '{' && format.charAt(i+1== '{' )
            {
                strOutput 
+= format.charAt(i);
                i
++
            }
            strOutput 
+= format.charAt(i);
            i
++;
        }
    }
    strOutput 
+= format.substr(i);
    
return strOutput.replace(/{{/g, '{').replace(/}}/g, '}');
 }

    开始的时候我使用Regular Expression来替换,结果发现问题巨多,多到我只能放弃了,老老实实的遍历替换。如果要保留"{"或"}",使用double来转义,和BCL类库String.Format用法完全一致。

    使用如下测试代码:
  alert(StringHelper.Format('{0}{0}, {{2}}, {{1}}', 'abc', 'def', 'ghi')); 

  alert(StringHelper.Format('{
0}, {{2}}, {1}', 'abc', 'def', 'ghi')); 

  alert(StringHelper.Format('{{
0}}\r\n, {2}\r\n, {1}', 'abc', 'def', 'ghi')); 

  alert(StringHelper.Format('{
0}{0}{{00}{0}, {{1}}, {{2}}', 'abc', 'def'));

    结果为:
 No.1 alert: abcabc, {2}, {1}

 No.2 alert: abc, {
2}, def

 No.3 alert: {
0}
                , ghi
                , def

 No.4 alert: abcabc{
00}abc, {1}, {2}

    您还有更好更高效的实现办法吗?

posted on 2005-03-08 00:05 birdshome 阅读(2822) 评论(7)  编辑 收藏 所属分类: Jscript&Dhtml开发

评论

#1楼    回复  引用    

已经很好了,平均扫一遍多一点,挺好的了,加之应用中字串多半不长。就算是设计一个状态机也必须扫满一遍

就是
var token = format.substr(i);
var index = String(token.match(/\d+/));
这里,如果不截取字串,不使用正则式就更好了,特别是正则式,开销不小

可以记下“{”的位置,继续扫直到不是数字,如果是“}”就怎么怎么,如果不是,从这个字符下一个开始继续。

你看这样好不好:
1、初始化,清“{”开始标记
2、看当前有无标记,无标记,转3;有标记,转4
3、(无标记)扫描当前字符是否为“{”,是转5,不是转8
4、(有标记)扫描当前字符是否为数字,是转8,不是转6
5、置“{”开始标记,并记录位置,转8
6、看当前字符是否为“{”,不是则转7,是则修正标记位置,转8
7、看当前字符是否为“}”,是且位置和记录的“{”位置差大于1,处理并清标记,否则清标记
8、当前位置++,是否没扫完format串?是,转2,不是,结束

算法没有涉及拷贝format剩余部分,还可以进一步在扫描数字时用s * 10 + x的方法得到{x}的x,则无须调用Number(str)了,其实肯定也是类似方法作的。

这样可能快一些,思考仓促,难免有失,还请斟酌
2005-03-08 00:45 | 问题男 [未注册用户]

#2楼    回复  引用  查看    

非常好的建议:) 取替换参数那里,我想起来数组下标使用字符串和数字效果是一样的,可能是内部做了默认转换。
2005-03-08 09:58 | birdshome      

#3楼    回复  引用    

有两个bug,一个是没有检查"}}"这种情况,就是说{0}}可以被替换。第二个就更严重了,如果有"{..}"这种结构,那个正则表达式其实不知道是取到的那个地方的数字。
2005-03-08 10:20 | yib [未注册用户]

#4楼    回复  引用    

/*
String对象扩展
By Gaoming On 2005.03.08
Email: Lonsan21@163.com
-- 欢迎交流和批评 --
*/
String.Format = function() {

if(arguments.length == 0)
return "";

if(arguments.length == 1)
return arguments[0];

var reg = /{(\d+)?}/g;
var args = arguments;
var result = arguments[0].replace(
reg,
function($0, $1) {
return args[parseInt($1)+1];
}
)

return result;
}

刚刚随手写了一个,考虑还不太全面,不能识别{{3}}格式,但是速度还是可以,供参考、交流。大家多提提 :)
2005-03-08 11:31 | Gaoming [未注册用户]

#5楼 [楼主]   回复  引用  查看    

单扫描版StringHelper.Format(),价格公道、童叟无欺,是居家旅行、杀人灭口必备方法。
2005-03-10 02:36 | birdshome      

#6楼    回复  引用    

前阵子我给as3写了个,纯re的,感觉没有你所说的bug...
http://user.qzone.qq.com/78545520/blog/1194539335
2007-12-02 21:21 | Fool [未注册用户]

#7楼    回复  引用    

在这里找到一个感觉比较好的:http://community.hdri.net/blogs/ray_blog/archive/2006/02/27/5.aspx

正在做的这个项目想代码更紧凑一点,所以修改了一下:
String.prototype.format=function(){
var str = this;
for(var i=0;i<arguments.length;str=str.replace(new RegExp('\\{'+(i)+'\\}','gm'),arguments[i++]));
return str;}
2008-07-23 11:46 | wormoapple [未注册用户]

标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      


相关链接: