sprintf for JavaScript

Avoid writing formatting functions in JavaScript by grabbing yourself a decent sprintf implementation – handling padding, truncation, floating-point numbers, left/right alignment and re-ordered arguments.

You can download sprintf for JavaScript, available under the Create Commons Attribution License. Now license free (use it where/when/how you like.)

The version I’ve written is based strongly on Perl’s sprintf implementation, allowing argument reordering to help with internationalisation (i18n). Some overly simplistic examples follow, leaving room for obvious improvements like:

  1. letting the user specify their locale as a preference
  2. set default locale based on visitor demographics
  3. use locale-specific message-bundles with a fall-back to the default locale

On with the examples:

var locale = 'es';
var messages = {
    'en': 'I am %d years and %d months old.',
    'es': 'Tengo %2$d meses y %1$d aƱos.'
};
var message = sprintf(messages[locale], 31, 7);

You could also use it for

var date = new Date;
var dateFormats = [
    /* ISO-8601: */ '%04d-%02d-%02d %02d:%02d:%02d',
    /* British:  */ '%3$02d/%2$02d/%1$02d',
    /* U.S.:     */ '%2$02d/%3$02d/%1$02d'
];

// for example only: choose random date format
var dateFormat = dateFormats[3 * Math.random() >>> 0];

var formatted = sprintf(dateFormat, 
    date.getFullYear(), date.getMonth() + 1, date.getDate(), 
    date.getHours(), date.getMinutes(), date.getSeconds());
alert(formatted);

The Perl documentation has more examples in the “order of arguments section“.
Note: this implementation allows the precision of a number to be set from a specific argument (using e.g. “%.*3$f”), which the perldocs (perldoc -f sprintf) say hasn’t been implemented yet.


I haven’t (re)written any documentation for it, but you should be able to use Firebug (or the javascript: protocol) to try out sprintf on this page, and you can also check out the test page for sprintf for more input/output samples.

As usual, writing test-cases uncovered a couple of browser-dependent issues. Safari has some bizarre behaviour with Maths.abs(0).toFixed(6) resulting in "0.0000-0" instead of "0.000000". Another issue I came across is that 0.5 rounds to 0 or 1 depending on browser (worded differently: numbers are rounded off inconsistently across browsers.)

Dependencies

On modern browsers, there are no dependencies. But to run sprintf on older browsers you’ll need to patch the Number and String objects. Number needs toFixed, toExponential and toPrecision methods, while String needs a replace method capable of using functions in the replacement parameter.

Posted in JavaScript
9 comments on “sprintf for JavaScript
  1. Psst… you shouldn’t use CC licenses for code (oh, I just realized that applies to your push() and pop() implementations too).

    (I’ll say something actually useful eventually!)

  2. Ash says:

    Quick response: if it’s good enough for Tantek, it’s good enough for me…

    I’ll have to think about whether to change to another license or whether to remove the license completely. Is it worth the time choosing between different open-source licenses?

    Does the license deter anyone from using the code?

  3. Ted Z says:

    Thanks for this great piece of code.

  4. Raphael says:

    Do you mind stating in the js lib that it is in the public domain and provide some contact information?

    I want to use it in a project (would solve tons of i18n problems on the client-side stuff) but I need those two points to be clarified.

  5. Dan Scott says:

    Ash:

    If you want to make the use of your code hassle-free, you could always offer your code under multiple licenses; putting code in the public domain is troublesome in some cases, too. Offering the code under multiple licenses means that you don’t have to choose between different open-source licenses; you could hit most of the sweet spots just by offering it under the GPL v2, the GPL v3, the revised BSD license, and the Apache License Version 2.

    We’re taking your code for a spin in http://open-ils.org at the moment, which is a project under the GPL v2; it would make things a little easier if your code was available under the GPL as well, but thanks in any case for your work and contributions!

  6. Lorenzo says:

    Thanks, exactly what i was looking for!

  7. Hi Ash,

    That’s an awesome function. Though it’s now license free I would still like to tell you that I’m including it in my php to javascript project. And so if you’re not okay with that or would like to be credited differently please drop a line here:
    http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_sprintf/

    Thanks!

  8. Ash says:

    Kevin,

    I see you gave me credit on your website and in the code – I can’t ask for any more than that.

    I appreciate the work you’re putting in to assembling the PHP equivalents, but boy… having used PHP for the last 12 months I really need to get off my arse and write an “I hate PHP” rant… The language really sucks, and I don’t have much hope PHP 6 will make things better…

  9. Amit Green says:

    Ash:

    I agree with the comment above by Dan Scott.

    Without proper licensing of your code, your code is unusable in many serious projects:

    1. The lawyers of a company, will pretty strongly insist that any code used have a proper license.

    2. Public domain, for the most part, is unacceptable to companies. There is no legally binding way for most people to place code into the public domain. (This is a ‘bug’ with public domain that Congress has not yet fixed).

    3. I also agree, with Dan Scott, you should license your code under a variety of license. This allows another project to incorporate your code with a license that matches their license.

    4. To explain furthur, as to why you want to license you code under multiple licenses: if a project is licensed under the MIT license, it prefers not to include code with a Apache License V2.0. Otherwise, by the time the project is using 10+ pieces of code, it is up to 5+ license, and it becomes a very messy license … which detracts from the overall project. Therefore, many projects, will avoid different licenses.

    5. Finally, yes, this whole licensing is a complete pain! It is *so* much nicer to just say “This code is unrestricted: you are free to use it however you like.” Unfortunatly, as hopefully this explains, this is not practical in our society, and you need to properly license your code, to make the greatest amount of people (mostly corporations) comfortable with using your code.

1 Pings/Trackbacks for "sprintf for JavaScript"