You can simplify the replacement by not translating the strings to numbers as all array subscripts are treated as strings, and by representing '{' and '}' as more user-friendly substitutions (e.g. {{} and {}}) rather than {-1} and {-2} which can be pre-populated into the replacements array. Also, the substitutable values can be passed as an arguments list rather than as a single array argument (again, simpler for the user). The net effect of these is that your function can be reduced to:
String.prototype.format = function() {
var args = arguments;
args['{'] = '{';
args['}'] = '}';
return this.replace(
/{({|}|-?[0-9]+)}/g,
function(item) {
var result = args[item.substring(1, item.length - 1)];
return typeof result == 'undefined' ? '' : result;
}
);
};
var str = "She {1} {0}{2} by the {0}{3}. {{}^_^{}}";
str = str.format("sea", "sells", "shells", "shore");
alert(str);
Note that not all versions of JavaScript support
string.replace(regexp, function)
. You can add support for it using:
if ('a'.replace(/a/, function() { return ''; }))
{
String.prototype._replaceNative = String.prototype.replace;
String.prototype.replace =
function(test, replacement)
{
if (typeof replacement == 'function')
if (typeof test == 'string')
{
var strs = this.split(test);
for (var i = 1; i < strs.length; i++)
strs[i - 1] += replacement(test);
return strs.join('');
}
else if (test.global)
{
var result = '';
test.lastIndex = 0;
do
{
var oldIndex = test.lastIndex;
test.exec(this);
if (test.lastIndex)
result += this.substring(oldIndex, RegExp.leftContext.length)
+ replacement(RegExp.lastMatch);
}
while (test.lastIndex);
return result + this.substring(oldIndex);
}
else
{
test.lastIndex = 0;
var results = test.exec(this);
return ( results
? this.substring(0, results.index)
+ replacement(results[0])
+ this.substring(results.index + results[0].length)
: this
);
}
else
{
arguments.constructor = Array;
return String.prototype._replaceNative.apply(this, arguments);
}
}
}