单扫描的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了

你可能感兴趣的:(string.Format)