单扫描的JScript版String.Format方法

    前天写了一个"JScript版的String.Format方法",本来都已经使用遍历法来替换格式化字符串了,结果却使用了RegExp和substr之类的憋脚方法。后来问题男很热心的给出了一个全扫描的方案,更郁闷的是由于自己对测试的认识不足,居然只使用了期望数据来测试代码,搞得bug一大坨

    于是在问题男的建议基础上,自己又作了一些优化,把整个替换操作一次扫描高定。代码如下: 
 // 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-1 ; )
    {
        
if ( format.charAt(i) == '{' && format.charAt(i+1!= '{' )
        {
            
var index = 0, indexStart = i+1;
            
for ( var j=indexStart ; j <= format.length-2 ; ++j )
            {
                
var ch = format.charAt(j);
                
if ( ch < '0|| ch > '9' ) break;
            }
            
if ( j > indexStart )
            {
                
if ( format.charAt(j) == '}' && format.charAt(j+1!= '}' )
                {
                     
for ( var k=j-1 ; k >= indexStart ; k-- )
                     {
                         index 
+= (format.charCodeAt(k)-48)*Math.pow(10, j-1-k);
                     }  
                    
var swapArg = arguments[index+1];
                    strOutput 
+= swapArg;
                    i 
+= j-indexStart+2;
                    
continue;
                }
            }
            strOutput 
+= format.charAt(i);
            i
++;
        }
        
else
        {
            
if ( ( format.charAt(i) == '{' && format.charAt(i+1== '{' )
                
|| ( format.charAt(i) == '}' && format.charAt(i+1== '}' ) )
            {
                i
++
            }
            strOutput 
+= format.charAt(i);
            i
++;
        }
    }
    strOutput 
+= format.substr(i);
    
return strOutput;
 }    

    相对上一版本的改进:
    1、不再使用RegExp和substr|substring;
    2、一次扫描完成所有替换和转义;
    3、修复了对"}}"扫描未做正确处理的bug;
    4、修复了取格式化条目编号可能出错的bug。

    新的测试数据:
 alert(StringHelper.Format('{0}', 'abc'));
 alert(StringHelper.Format('{
0}}{0}, {{2}, {1}}', 'abc', 'def', 'ghi'));    
 alert(StringHelper.Format('{
000}, {{{{2}}}}, {001}', 'abc', 'def', 'ghi'));    
 alert(StringHelper.Format('{{
0}}\r\n2, {2}\r\n, {1}', 'abc', 'def', 'ghi'));    
 alert(StringHelper.Format('{
0}{0}{0}, {0{1}0}, {{{{{2}}}', 'abc', 'def'));

    测试所得结果:
 No.1 alert: abc

 No.2 alert: {0}abc, {2}, {1}


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

 No.4 alert: {
0}
                2, ghi
                , def

 No.5 alert: abcabcabc, {0def0}, {{{2}}

    继续征集更优化方案:)

    BTW: 代码中使用了一个JavaScript的Syntax Sugar来减少代码,你看循环:
 for ( var i=0 ; i < format.length-1 ; )
 {
    
if ( ... )
    {
        
// . . .
    }
    
else
    {
        format.charAt(i
+i)
    }
 }

    显然i+1已经溢出了字符串的长度了,不过这时根本不用管它,JavaScript会返回一个undefined,这个值完全不会影响我们的程序逻辑。如果是C#就需要啰里啰唆的去判断i+1是不是小于format.length,否则就Index Out of Range Exception了

posted on 2005-03-10 00:09  birdshome  阅读(4188)  评论(16编辑  收藏  举报

导航