String Formatting in JavaScript
I am a relative newcomer to python, and have been blown away by the flexibility of some operations in Python. The string-formatting operator, %, is really wonderful and flexible. This is my attempt at implementing something similar in JavaScript.
Obviously, you can’t create a new operator in JavaScript, and in addition you can’t use % as a JavaScript identifier. So I went for the next-best thing:
String.prototype.format = function string_format(d) { // there are two modes of operation... unnamed indices are read in order; // named indices using %(name)s. The two styles cannot be mixed. // Unnamed indices can be passed as either a single argument to this function, // multiple arguments to this function, or as a single array argument let curindex = 0; if (arguments.length > 1) d = arguments; function r(s, key, type) { let v; if (key == "") { if (curindex == -1) throw Error("Cannot mix named and positional indices in string formatting."); if (curindex == 0 && (!(d instanceof Object) || !(0 in d))) v = d; else if (!(curindex in d)) throw Error("Insufficient number of items in format, requesting item %i".format(curindex)); else v = d[curindex]; ++curindex; } else { key = key.slice(1, -1); if (curindex > 0) throw Error("Cannot mix named and positional indices in string formatting."); curindex = -1; if (!(key in d)) throw Error("Key '%s' not present during string substitution.".format(key)); v = d[key]; } switch (type) { case "s": return v.toString(); case "r": return v.toSource(); case "i": return parseInt(v); case "f": return Number(v); case "%": return "%"; default: throw Error("Unexpected format character '%s'.".format(type)); } } return this.replace(/%(\([^)]+\))?(.)/g, r); }; String.prototype.ø = String.prototype.format;
If you are at all familiar with the python string-formatting operator, this should be very similar:
"%s %s".ø("angry", "monkeys"); == "angry monkeys"; "%(key)s: %(value)s".ø({key: 'bananas', value: 'tasty'}) == "bananas: tasty"; "%i - %i".ø([1, 3]) == "1 - 3"; "%r".ø(['α', 'ω'] == '["α", "ω"]';
I know that there are many sprintf-like libraries out there for JavaScript: I just happen to like mine best. Caution: this code requires JavaScript 1.7… if you replace some “let”s with “var”s it may work in older browsers, but I haven’t tested it.
Being able to pass a function as a replacement in String.replace is a very powerful feature!
July 15th, 2008 at 6:15 pm
Python’s % should be considered obsolete, with format() being the recommended replacement in Python 3.
I would look at duplicating format() instead of %.
July 15th, 2008 at 6:33 pm
You named your anonymous function: “String.prototype.format = function string_format(d) {” Is that just a bug or intended? Calling string_format() doesn’t seem to work.
Anyway! Really nice stuff, I think I’ll keep this one around. The syntax is really elegant. Man, I should really learn Python.
July 15th, 2008 at 7:00 pm
Why do you use “let” anyway? Does it make any difference in this case?
July 15th, 2008 at 8:02 pm
Anonymous: the proposed .format() replacement uses keyword args, which are not supported by JavaScript. I’ll stick with this version.
Michael: I name my anonymous functions so that backtraces and debuggers see them with a name. I wouldn’t expect you to call it directly.
Dao: I use let because I wrote this code for a dehydra analysis in which we don’t use var scope at all, for consistency and readability.
July 16th, 2008 at 2:40 pm
Not so long ago I’ve implemented Python3K’s string formating for jQuery, it was quite fun I must admit.
> Anonymous: the proposed .format() replacement uses keyword args, which are not supported by JavaScript. I’ll stick with this version.
It’s easy to work around, just use annotated objects as parameter..
Anyway, it shouldn’t be considered as an equivalent to Python’s string formating, I’ve implemented it the best I could but JavaScript has its limitation.
The code:
http://code.google.com/p/jquery-utils/source/browse/trunk/src/jquery.strings.js
Doc:
http://code.google.com/p/jquery-utils/wiki/StringFormat
Blog post:
http://haineault.com/blog/58/
Cheers
November 20th, 2008 at 12:57 am
Hey, I like your library. There’s a tiny bug that makes it incompatible with Safari tho. Here’s a patch for the fix:
Index: string_formatting.js
===================================================================
— string_formatting.js (revision 28)
+++ string_formatting.js (working copy)
@@ -10,7 +10,7 @@
function r(s, key, type) {
var v;
– if (key == “”) {
+ if (!key || key == “”) {
if (curindex == -1)
throw Error(“Cannot mix named and positional indices in string formatting.”);
April 29th, 2009 at 10:12 pm
Brilliant. Very creative making a new operator. This is the type of ingenuity that uses JavaScript in a brilliant and useful way, rather than using it as lipstick on a pig (a common practice in web design anymore)