于是在问题男的建议基础上,自己又作了一些优化,把整个替换操作一次扫描高定。代码如下:
// 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&#61;0 ; i < format.length-1 ; )
{
if ( format.charAt(i) &#61;&#61; &#39;{&#39; && format.charAt(i&#43;1) !&#61; &#39;{&#39; )
{
var index &#61; 0, indexStart &#61; i&#43;1;
for ( var j&#61;indexStart ; j <&#61; format.length-2 ; &#43;&#43;j )
{
var ch &#61; format.charAt(j);
if ( ch < &#39;0&#39; || ch > &#39;9&#39; ) break;
}
if ( j > indexStart )
{
if ( format.charAt(j) &#61;&#61; &#39;}&#39; && format.charAt(j&#43;1) !&#61; &#39;}&#39; )
{
for ( var k&#61;j-1 ; k >&#61; indexStart ; k-- )
{
index &#43;&#61; (format.charCodeAt(k)-48)*Math.pow(10, j-1-k);
}
var swapArg &#61; arguments[index&#43;1];
strOutput &#43;&#61; swapArg;
i &#43;&#61; j-indexStart&#43;2;
continue;
}
}
strOutput &#43;&#61; format.charAt(i);
i&#43;&#43;;
}
else
{
if ( ( format.charAt(i) &#61;&#61; &#39;{&#39; && format.charAt(i&#43;1) &#61;&#61; &#39;{&#39; )
|| ( format.charAt(i) &#61;&#61; &#39;}&#39; && format.charAt(i&#43;1) &#61;&#61; &#39;}&#39; ) )
{
i&#43;&#43;
}
strOutput &#43;&#61; format.charAt(i);
i&#43;&#43;;
}
}
strOutput &#43;&#61; format.substr(i);
return strOutput;
}
// return "abc, ghi, def".
StringHelper.Format &#61; function(format)
{
if ( arguments.length &#61;&#61; 0 )
{
return &#39;&#39;;
}
if ( arguments.length &#61;&#61; 1 )
{
return String(format);
}
var strOutput &#61; &#39;&#39;;
for ( var i&#61;0 ; i < format.length-1 ; )
{
if ( format.charAt(i) &#61;&#61; &#39;{&#39; && format.charAt(i&#43;1) !&#61; &#39;{&#39; )
{
var index &#61; 0, indexStart &#61; i&#43;1;
for ( var j&#61;indexStart ; j <&#61; format.length-2 ; &#43;&#43;j )
{
var ch &#61; format.charAt(j);
if ( ch < &#39;0&#39; || ch > &#39;9&#39; ) break;
}
if ( j > indexStart )
{
if ( format.charAt(j) &#61;&#61; &#39;}&#39; && format.charAt(j&#43;1) !&#61; &#39;}&#39; )
{
for ( var k&#61;j-1 ; k >&#61; indexStart ; k-- )
{
index &#43;&#61; (format.charCodeAt(k)-48)*Math.pow(10, j-1-k);
}
var swapArg &#61; arguments[index&#43;1];
strOutput &#43;&#61; swapArg;
i &#43;&#61; j-indexStart&#43;2;
continue;
}
}
strOutput &#43;&#61; format.charAt(i);
i&#43;&#43;;
}
else
{
if ( ( format.charAt(i) &#61;&#61; &#39;{&#39; && format.charAt(i&#43;1) &#61;&#61; &#39;{&#39; )
|| ( format.charAt(i) &#61;&#61; &#39;}&#39; && format.charAt(i&#43;1) &#61;&#61; &#39;}&#39; ) )
{
i&#43;&#43;
}
strOutput &#43;&#61; format.charAt(i);
i&#43;&#43;;
}
}
strOutput &#43;&#61; format.substr(i);
return strOutput;
}
相对上一版本的改进&#xff1a;
1、不再使用RegExp和substr|substring&#xff1b;
2、一次扫描完成所有替换和转义&#xff1b;
3、修复了对"}}"扫描未做正确处理的bug&#xff1b;
4、修复了取格式化条目编号可能出错的bug。
新的测试数据&#xff1a;
alert(StringHelper.Format(&#39;{0}&#39;, &#39;abc&#39;));
alert(StringHelper.Format(&#39;{0}}{0}, {{2}, {1}}&#39;, &#39;abc&#39;, &#39;def&#39;, &#39;ghi&#39;));
alert(StringHelper.Format(&#39;{000}, {{{{2}}}}, {001}&#39;, &#39;abc&#39;, &#39;def&#39;, &#39;ghi&#39;));
alert(StringHelper.Format(&#39;{{0}}\r\n2, {2}\r\n, {1}&#39;, &#39;abc&#39;, &#39;def&#39;, &#39;ghi&#39;));
alert(StringHelper.Format(&#39;{0}{0}{0}, {0{1}0}, {{{{{2}}}&#39;, &#39;abc&#39;, &#39;def&#39;));
alert(StringHelper.Format(&#39;{0}}{0}, {{2}, {1}}&#39;, &#39;abc&#39;, &#39;def&#39;, &#39;ghi&#39;));
alert(StringHelper.Format(&#39;{000}, {{{{2}}}}, {001}&#39;, &#39;abc&#39;, &#39;def&#39;, &#39;ghi&#39;));
alert(StringHelper.Format(&#39;{{0}}\r\n2, {2}\r\n, {1}&#39;, &#39;abc&#39;, &#39;def&#39;, &#39;ghi&#39;));
alert(StringHelper.Format(&#39;{0}{0}{0}, {0{1}0}, {{{{{2}}}&#39;, &#39;abc&#39;, &#39;def&#39;));
测试所得结果&#xff1a;
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}}
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来减少代码&#xff0c;你看循环&#xff1a;
for ( var i&#61;0 ; i < format.length-1 ; )
{
if ( ... )
{
// . . .
}
else
{
format.charAt(i&#43;i)
}
}
{
if ( ... )
{
// . . .
}
else
{
format.charAt(i&#43;i)
}
}
显然i&#43;1已经溢出了字符串的长度了&#xff0c;不过这时根本不用管它&#xff0c;Javascript会返回一个undefined&#xff0c;这个值完全不会影响我们的程序逻辑。如果是C#就需要啰里啰唆的去判断i&#43;1是不是小于format.length&#xff0c;否则就Index Out of Range Exception了。