>For ages, I have relied on Douglas Crockford’s excellent supplant() for my string formatting needs in JS. It works great with whatever objects you have already hanging around in your code:
var myObj = { name: "Conan", surname: "The Barbarian" };
"{name} {surname}".supplant(myObj);
// result:
"Conan The Barbarian"
This is great, reliable and all that…
But it is a bit verbose in the cases where you do not already have an object hanging around with the correct properties. I tried to find an existing implementation, but most of them were still too verbose relying on hacks like: “{$1} {$2}” or “$1 $2” or worse.
I want a “printf” or Python-style string interpolation:
#python
"%s %s" % ("Conan", "The Barbarian",)
// result:
"Conan The Barbarian"
That’s what I want! – only for strings, it doesn’t have to be too feature-rich. Eventually it would be nice if it could handle integers and floats etc.
After some questions and answers on irc in #js, I was able to get something rudimentary going. I started with supplant, and added support for arrays and arguments.
Behold! String.printf():
String.prototype.printf = function (obj) {
var useArguments = false;
var _arguments = arguments;
var i = -1;
if (typeof _arguments[0] == "string") {
useArguments = true;
}
if (obj instanceof Array || useArguments) {
return this.replace(/\%s/g,
function (a, b) {
i++;
if (useArguments) {
if (typeof _arguments[i] == 'string') {
return _arguments[i];
}
else {
throw new Error("Arguments element is an invalid type");
}
}
return obj[i];
});
}
else {
return this.replace(/{([^{}]*)}/g,
function (a, b) {
var r = obj[b];
return typeof r === 'string' || typeof r === 'number' ? r : a;
});
}
};
Examples:
"{f} {b}".printf({f: "foo", b: "bar"});
"%s %s".printf(["foo", "bar"]);
"%s %s".printf("foo", "bar");
// all of which give this result:
"foo bar"
Let me know if you think of more tweaks for this – or problems. It pains me every time I see concatenation in JS code. Question, which is more efficient? ‘+’ or String.replace()?
Cheers!