单扫描的JScript版String.Format方法
前天写了一个"JScript版的String.Format方法",本来都已经使用遍历法来替换格式化字符串了,结果却使用了RegExp和substr之类的憋脚方法。后来问题男很热心的给出了一个全扫描的方案,更郁闷的是由于自己对测试的认识不足,居然只使用了期望数据来测试代码,搞得bug一大坨。
于是在问题男的建议基础上,自己又作了一些优化,把整个替换操作一次扫描高定。代码如下:
相对上一版本的改进:
1、不再使用RegExp和substr|substring;
2、一次扫描完成所有替换和转义;
3、修复了对"}}"扫描未做正确处理的bug;
4、修复了取格式化条目编号可能出错的bug。
新的测试数据:
测试所得结果:
继续征集更优化方案:)
BTW: 代码中使用了一个JavaScript的Syntax Sugar来减少代码,你看循环:
显然i+1已经溢出了字符串的长度了,不过这时根本不用管它,JavaScript会返回一个undefined,这个值完全不会影响我们的程序逻辑。如果是C#就需要啰里啰唆的去判断i+1是不是小于format.length,否则就Index Out of Range Exception了。
于是在问题男的建议基础上,自己又作了一些优化,把整个替换操作一次扫描高定。代码如下:
// 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;
}
// 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'));
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}}
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)
}
}
{
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) 编辑 收藏 举报