Python has this beautiful function to turn this:
bar1 = \'foobar\'
bar2 = \'jumped\'
bar3 = \'dog\'
foo = \'The lazy \' + bar3 + \' \' + bar2 \' over the \'
String.prototype.format = function () {
var i=0,args=arguments,formats={
"f":(v,s,c,f)=>{s=s||' ',c=parseInt(c||'0'),f=parseInt(f||'-1');v=f>0?Math.floor(v).toString()+"."+Math.ceil(v*Math.pow(10,f)).toString().slice(-f):(f==-1?v.toString():Math.floor(v).toString());return c>v.length?s.repeat(c-v.length)+v:v;},
"d":(v,s,c,f)=>{s=s||' ',c=parseInt(c||'0');v=Math.floor(v).toString();return c>v.length?s.repeat(c-v.length)+v:v;},
"s":(v,s,c,f)=>{s=s||' ',c=parseInt(c||'0');return c>v.length?s.repeat(c-v.length)+v:v;},
"x":(v,s,c,f)=>{s=s||' ',c=parseInt(c||'0');v=Math.floor(v).toString(16);return c>v.length?s.repeat(c-v.length)+v:v;},
"X":(v,s,c,f)=>{s=s||' ',c=parseInt(c||'0');v=Math.floor(v).toString(16).toUpperCase();return c>v.length?s.repeat(c-v.length)+v:v;},
};
return this.replace(/{(\d+)?:?([0=-_*])?(\d+)?\.?(\d+)?([dfsxX])}/g, function () {
let pos = arguments[1]||i;i++;
return typeof args[pos] != 'undefined' ? formats[arguments[5]](args[pos],arguments[2],arguments[3],arguments[4]) : '';
});
};
Looking for an answer for the same question, I just found this: https://github.com/davidchambers/string-format, which is "JavaScript string formatting inspired by Python’s str.format()
". It seem it's pretty much the same as python's format()
function.
foo = (a, b, c) => `The lazy ${a} ${b} over the ${c}`
ES6 template strings provide a feature quite similar to pythons string format. However, you have to know the variables before you construct the string:
var templateString = `The lazy ${bar3} ${bar2} over the ${bar1}`;
Python's str.format
allows you to specify the string before you even know which values you want to plug into it, like:
foo = 'The lazy {} {} over the {}'
bar1 = 'foobar'
bar2 = 'jumped'
bar3 = 'dog'
foo.format(bar3, bar2, bar1)
With an arrow function, we can elegantly wrap the template string for later use:
foo = (a, b, c) => `The lazy ${a} ${b} over the ${c}`
bar1 = 'foobar';
bar2 = 'jumped';
bar3 = 'dog';
foo(bar3, bar2, bar1)
Of course this works with a regular function as well, but the arrow function allows us to make this a one-liner. Both features are available in most browsers und runtimes:
Here's my first attempt. Feel free to point out flaws.
Example: http://jsfiddle.net/wFb2p/5/
String.prototype.format = function() {
var str = this;
var i = 0;
var len = arguments.length;
var matches = str.match(/{}/g);
if( !matches || matches.length !== len ) {
throw "wrong number of arguments";
}
while( i < len ) {
str = str.replace(/{}/, arguments[i] );
i++;
}
return str;
};
EDIT: Made it a bit more efficient by eliminating the .match()
call in the while
statement.
EDIT: Changed it so that the same error is thrown if you don't pass any arguments.
If you (like me) only need the limited subset of python's format function for simple string replacement, and performance is not critical, a very simple 29-line pure-Javascript function may suffice.
Javascript call: format(str, data)
Analogous python call: str.format(**data)
, with the caveat that this javascript function, unlike Python's, does not throw an error if the string contains a varname that is not found in the provided data.
/*
* format(str, data): analogous to Python's str.format(**data)
*
* Example:
* let data = {
* user: {
* name: { first: 'Jane', last: 'Doe' }
* },
* email: 'jane@doe.com',
* groups: ["one","two"]
* };
*
* let str = 'Hi {user.name.first} {user.name.last}, your email address is {email}, and your second group is {groups[1]}'
*
* format(str, data)
* => returns "Hi Jane Doe, your email address is jane@doe.com, and your second group is two"
*/
function format(str, data) {
var varnames = {};
function array_path(path, i) {
var this_k = '[' + i + ']';
if (!path.length)
return [this_k];
path = path.slice();
path[path.length - 1] += this_k;
return path;
}
function add_varnames(this_data, path) {
if (this_data.constructor == Array) {
for (var i = 0; i < this_data.length; i++)
add_varnames(this_data[i], array_path(path, i));
}
else if (this_data.constructor == Object) {
for (var k in this_data)
add_varnames(this_data[k], path.concat(k));
}
else {
var varname = '{' + path.join('.') + '}';
varnames[varname] = String(this_data);
}
}
add_varnames(data, []);
for (var varname in varnames)
str = str.replace(varname, varnames[varname]);
return str;
}
JavaScript doesn't have such a function AFAIK.
You could create one by modifying the String class's prototype object to add a format() method which takes a variable number of arguments.
In the format method you'd have to get the String's instance value (the actual string) and then parse it for '{}' and insert the appropriate argument.
Then return the new string to the caller.