>Everybody needs a little printf in their JavaScript

2010/01/12 — 7 Comments

>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!

Advertisements

7 responses to >Everybody needs a little printf in their JavaScript

  1. 

    >Not a big fan of printf-style formatting – I prefer syntax where the order of placeholders isn't tied to the order of parameters.Python has a newer style for String formatting that I quite like, supporting both keyword and positional parameters – under it, your first example would be something like:myObj = { 'name':"Conan", surname':"The Barbarian" };"{0.name} {0.surname}".format(myObj)Or you could do:"{name} {surname}".format(name="Conan", surname="The Barbarian")or:"{0} {1}".format("Conan", "The Barbarian")Your mileage may very, but it suits me perfectly… something similar ought to be possible in javascript…

  2. 

    >I miss you python! Don't get me started on the superiority of argument handling in python, e.g: *args and **kwargs.I may have called it String.printf, but it handles 3 approaches: object substitutions, array and arguments. Which is as close to pythonesque as you can get without hacking on JS itself.

  3. 

    >I wrote a String.format function which can take ordered or named parameters python-style, see http://benjamin.smedbergs.us/blog/2008-07-15/string-formatting-in-javascript/

  4. 

    >Benjamin:As usual, my research into existing implementations was lacking. I like your ".0()" approach. Something like this should just be a part of JS in Firefox.

  5. 

    >This isn't an OO approach, but someone has already implemented ALL of printf/sprintf in js:http://phpjs.org/functions/printf:494http://phpjs.org/functions/sprintf:522

  6. 

    The name printf is misleading. This should really be called format (or at least sprintf), as it returns a string. A printf function should print directly to an output stream.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s