JavaScript相当于printf / string.format

我正在寻找一个相当于C / PHP的printf()或C#/ Java程序员的String.Format()IFormatProvider for .NET)的JavaScript。

我现在的基本要求是数字分隔格式,但是处理大量组合(包括date)的东西是很好的。

我意识到微软的Ajax库提供了一个String.Format()的版本,但是我们并不希望整个这个框架的开销。

尝试用于JavaScript的sprintf() 。


更新好了,如果你真的想自己做一个简单的格式化方法,不要连续做replace,而是同时做。

由于大多数提到的其他提议都失败了,因为以前replace的replacestring也包含这样的格式序列:

 "{0}{1}".format("{1}", "{0}") 

通常情况下,您会预期输出为{1}{0}但实际输出为{1}{1} 。 所以做一个同时更换,而不是像fearphage的build议 。

build立在以前build议的解决scheme上:

 // First, checks if it isn't implemented yet. if (!String.prototype.format) { String.prototype.format = function() { var args = arguments; return this.replace(/{(\d+)}/g, function(match, number) { return typeof args[number] != 'undefined' ? args[number] : match ; }); }; } 

"{0} is dead, but {1} is alive! {0} {2}".format("ASP", "ASP.NET")

输出

ASP已经死了,但ASP.NET还活着! ASP {2}


如果你不想修改String的原型:

 if (!String.format) { String.format = function(format) { var args = Array.prototype.slice.call(arguments, 1); return format.replace(/{(\d+)}/g, function(match, number) { return typeof args[number] != 'undefined' ? args[number] : match ; }); }; } 

给你更熟悉的:

String.format('{0} is dead, but {1} is alive! {0} {2}', 'ASP', 'ASP.NET');

结果相同:

ASP已经死了,但ASP.NET还活着! ASP {2}

这很有趣,因为堆栈溢出实际上有一个名为formatUnicornString原型的格式化函数。 尝试一下! 进入控制台并input如下所示的内容:

 "Hello, {name}, are you feeling {adjective}?".formatUnicorn({name:"Gabriel", adjective: "OK"}); 

萤火

你得到这个输出:

Hello, Gabriel, are you feeling OK?

您可以使用对象,数组和string作为参数! 我得到了它的代码,并重新编写了一个新的String.prototype.format版本:

 String.prototype.formatUnicorn = String.prototype.formatUnicorn || function () { "use strict"; var str = this.toString(); if (arguments.length) { var t = typeof arguments[0]; var key; var args = ("string" === t || "number" === t) ? Array.prototype.slice.call(arguments) : arguments[0]; for (key in args) { str = str.replace(new RegExp("\\{" + key + "\\}", "gi"), args[key]); } } return str; }; 

注意聪明的Array.prototype.slice.call(arguments)调用 – 这意味着如果抛出的是string或数字的参数,而不是一个单一的JSON风格的对象,那么您几乎可以得到C#的String.Format行为。

 "a{0}bcd{1}ef".formatUnicorn("foo", "bar"); // yields "aFOObcdBARef" 

这是因为Arrayslice会强制任何arguments到一个Array ,无论它是否是原来的, key将是每个数组元素的索引(0,1,2 …)强制为一个string(例如, “0”,所以"\\{0\\}"为您的第一个正则expression式模式)。

整齐。

在JavaScript中的数字格式

我到了这个问题页面,希望能够find如何在JavaScript中格式化数字 ,而不需要引入另一个库。 这是我发现的:

舍入浮点数

在JavaScript中相当于sprintf("%.2f", num)似乎是num.toFixed(2) ,它将num格式设置为2个小数位,舍入(但请参阅下面关于Math.round @ ars265的注释)。

 12.345.toFixed(2); // returns "12.35" (rounding!) 12.3.toFixed(2); // returns "12.30" (zero padding) 

指数forms

sprintf("%.2e", num)的等价物是num.toExponential(2)

 33333 .toExponential(2); // "3.33e+4" // ^ Note the space, which keeps the . from being a decimal point. // Leaving out the space is a syntax error :-( 

hex等基地

要打印基数B中的数字,请尝试num.toString(B) 。 JavaScript支持从2到36的自动转换(此外,一些浏览器对base64编码的支持有限 )。

 3735928559 .toString(16); // to base 16: "deadbeef" parseInt("deadbeef", 16); // from base 16: 3735928559 

参考页面

JS数字格式的快速教程

toFixed()的链接到toPrecision(),toExponential(),toLocaleString(),…)

jsxt,Zippo

这个选项更合适。

 String.prototype.format = function() { var formatted = this; for (var i = 0; i < arguments.length; i++) { var regexp = new RegExp('\\{'+i+'\\}', 'gi'); formatted = formatted.replace(regexp, arguments[i]); } return formatted; }; 

有了这个选项,我可以replace这样的string:

 'The {0} is dead. Don\'t code {0}. Code {1} that is open source!'.format('ASP', 'PHP'); 

用你的代码,第二个{0}不会被replace。 ;)

从ES6上你可以使用模板string

 let soMany = 10; console.log(`This is ${soMany} times easier!`); // "This is 10 times easier! 

请注意,模板string被反引号包围而不是(单个)引号。

了解更多信息:

https://developers.google.com/web/updates/2015/01/ES6-Template-Strings

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/template_strings

注意:检查mozilla站点以查找支持的浏览器列表。

我使用这个简单的function:

 String.prototype.format = function() { var formatted = this; for( var arg in arguments ) { formatted = formatted.replace("{" + arg + "}", arguments[arg]); } return formatted; }; 

这与string.format非常相似:

 "{0} is dead, but {1} is alive!".format("ASP", "ASP.NET") 

下面是JavaScript中sprintf的最小实现:它只做“%s”和“%d”,但是我留下了空间来扩展它。 这对于OP来说是没有用的,但是其他人却偶然发现这个来自Google的线索可能会从中受益。

 function sprintf() { var args = arguments, string = args[0], i = 1; return string.replace(/%((%)|s|d)/g, function (m) { // m is the matched format, eg %s, %d var val = null; if (m[2]) { val = m[2]; } else { val = args[i]; // A switch statement so that the formatter can be extended. Default is %s switch (m) { case '%d': val = parseFloat(val); if (isNaN(val)) { val = 0; } break; } i++; } return val; }); } 

例:

 alert(sprintf('Latitude: %s, Longitude: %s, Count: %d', 41.847, -87.661, 'two')); // Expected output: Latitude: 41.847, Longitude: -87.661, Count: 0 

与之前的回复中的类似解决scheme相比,这个方法一次性完成所有的replace,所以它不会replace以前replace的部分值。

对于Node.js用户,有util.format具有类似printf的function:

 util.format("%s world", "Hello") 

JavaScript程序员可以使用https://github.com/ildar-shaimordanov/jsxt/blob/master/js/String.js中的; String.prototype.sprintf。 下面是例子:

 var d = new Date(); var dateStr = '%02d:%02d:%02d'.sprintf( d.getHours(), d.getMinutes(), d.getSeconds()); 

我很惊讶没有人使用过reduce ,这是一个原生的JavaScript处事方式,非常简洁和强大。

 var _r=function(p,c){return p.replace(/%s/,c);} var x = ["a", "b", "c"].reduce(_r, "[%s], [%s] and [%s]"); // [a], [b] and [c] var y = [1, 2, 3].reduce(_r, "%s+%s=%s"); // 1+2=3 var z = ["cool", 1337, "stuff"].reduce(_r, "%s %s %s"); // cool 1337 stuff 

编辑:这是一个function,你可以插入任何地方做replace。

 function interpolate(theString, argumentArray) { var regex = /%s/; var _r=function(p,c){return p.replace(regex,c);} return argumentArray.reduce(_r, theString); } interpolate("%s, %s and %s", ["Me", "myself", "I"]); // "Me, myself and I" 

+1 Zippo,除了函数体需要如下所示,否则它会在每次迭代时附加当前string:

 String.prototype.format = function() { var formatted = this; for (var arg in arguments) { formatted = formatted.replace("{" + arg + "}", arguments[arg]); } return formatted; }; 

我会添加我自己发现的新发现,

  • number_format(千位分隔符/货币格式)
  • sprintf(与上面相同的作者)

可悲的是,似乎sprintf不处理像.NET的string格式的千位分隔符格式。

我使用一个名为String.format的小型库,它支持大多数格式stringfunction(包括数字和date格式),并使用.NET语法。 脚本本身小于4 kB,所以不会产生太多的开销。

十分优雅:

 String.prototype.format = function (){ var args = arguments; return this.replace(/\{\{|\}\}|\{(\d+)\}/g, function (curlyBrack, index) { return ((curlyBrack == "{{") ? "{" : ((curlyBrack == "}}") ? "}" : args[index])); }); }; // Usage: "{0}{1}".format("{1}", "{0}") 

信贷去 (断开链接) https://gist.github.com/0i0/1519811

添加到zippoxer的答案,我使用这个函数:

 String.prototype.format = function(){ var a = this, b; for(b in arguments){ a = a.replace(/%[az]/,arguments[b]); } return a; // Make chainable }; var s = 'Hello %s The magic number is %d.'; s.format('world!', 12); // Hello World! The magic number is 12. 

我也有一个非原型版本,我更经常使用它的类似Java的语法:

 function format(){ var a,b,c; a = arguments[0]; b = []; for(c = 1; c < arguments.length; c++){ b.push(arguments[c]); } for(c in b){ a = a.replace(/%[az]/,b[c]); } return a; }; format('%d ducks, 55 %s', 12, 'cats'); // 12 ducks, 55 cats 

ES 2015更新

ES 2015中所有酷炫的新东西使得这一切变得更加简单:

 function format(fmt, ...args){ return fmt .split("%%") .reduce((aggregate, chunk, i) => aggregate + chunk + (args[i] || ""), ""); } format("Hello %%! I ate %% apples today.", "World", 44); // "Hello World, I ate 44 apples today." 

我认为,既然这样,像老一样,实际上并没有parsing这些字母,它可能只是使用一个单一的记号%% 。 这具有显而易见的好处,并且使得难以使用单个% 。 但是,如果您出于某种原因需要%% ,则需要将其replace为自己:

 format("I love percentage signs! %%", "%%"); // "I love percentage signs! %%" 

我想分享我的“问题”的解决scheme。 我没有重新发明轮子,但试图find一个基于JavaScript已经做的解决scheme。 优点是,您可以免费获得所有隐式转换。 设置String的原型属性$给出了一个非常好的和紧凑的语法(参见下面的例子)。 这也许不是最有效的方式,但是在大多数情况下,处理输出并不需要超级优化。

 String.form = function(str, arr) { var i = -1; function callback(exp, p0, p1, p2, p3, p4) { if (exp=='%%') return '%'; if (arr[++i]===undefined) return undefined; var exp = p2 ? parseInt(p2.substr(1)) : undefined; var base = p3 ? parseInt(p3.substr(1)) : undefined; var val; switch (p4) { case 's': val = arr[i]; break; case 'c': val = arr[i][0]; break; case 'f': val = parseFloat(arr[i]).toFixed(exp); break; case 'p': val = parseFloat(arr[i]).toPrecision(exp); break; case 'e': val = parseFloat(arr[i]).toExponential(exp); break; case 'x': val = parseInt(arr[i]).toString(base?base:16); break; case 'd': val = parseFloat(parseInt(arr[i], base?base:10).toPrecision(exp)).toFixed(0); break; } val = typeof(val)=='object' ? JSON.stringify(val) : val.toString(base); var sz = parseInt(p1); /* padding size */ var ch = p1 && p1[0]=='0' ? '0' : ' '; /* isnull? */ while (val.length<sz) val = p0 !== undefined ? val+ch : ch+val; /* isminus? */ return val; } var regex = /%(-)?(0?[0-9]+)?([.][0-9]+)?([#][0-9]+)?([scfpexd])/g; return str.replace(regex, callback); } String.prototype.$ = function() { return String.form(this, Array.prototype.slice.call(arguments)); } 

这里有几个例子:

 String.format("%s %s", [ "This is a string", 11 ])) console.out("%s %s".$("This is a string", 11)) var arr = [ "12.3", 13.6 ]; console.out("Array: %s".$(arr)); var obj = { test:"test", id:12 }; console.out("Object: %s".$(obj)); console.out("%c", "Test"); console.out("%5d".$(12)); // ' 12' console.out("%05d".$(12)); // '00012' console.out("%-5d".$(12)); // '12 ' console.out("%5.2d".$(123)); // ' 120' console.out("%5.2f".$(1.1)); // ' 1.10' console.out("%10.2e".$(1.1)); // ' 1.10e+0' console.out("%5.3p".$(1.12345)); // ' 1.12' console.out("%5x".$(45054)); // ' affe' console.out("%20#2x".$("45054")); // ' 1010111111111110' console.out("%6#2d".$("111")); // ' 7' console.out("%6#16d".$("affe")); // ' 45054' 

如果你想要处理千位分隔符,你应该使用JavaScript Number类的toLocaleString(),因为它将格式化用户区域的string。

JavaScript Date类可以格式化本地化的date和时间。

PHPJS项目为许多PHP函数编写了JavaScript实现。 由于PHP的sprintf()函数基本上与C的printf()相同,所以它的JavaScript实现应该满足您的需求。

我使用这个:

 String.prototype.format = function() { var newStr = this, i = 0; while (/%s/.test(newStr)) newStr = newStr.replace("%s", arguments[i++]) return newStr; } 

然后我称之为:

 "<h1>%s</h1><p>%s</p>".format("Header", "Just a test!"); 

一个非常不同的版本,我喜欢的版本(这个使用{xxx}令牌而不是{0}编号的参数,这是更自我logging和适合本地化更好):

 String.prototype.format = function(tokens) { var formatted = this; for (var token in tokens) if (tokens.hasOwnProperty(token)) formatted = formatted.replace(RegExp("{" + token + "}", "g"), tokens[token]); return formatted; }; 

变化将是:

  var formatted = l(this); 

先调用l()本地化函数。

我有一个非常接近彼得的解决scheme,但它涉及数量和对象的情况。

 if (!String.prototype.format) { String.prototype.format = function() { var args; args = arguments; if (args.length === 1 && args[0] !== null && typeof args[0] === 'object') { args = args[0]; } return this.replace(/{([^}]*)}/g, function(match, key) { return (typeof args[key] !== "undefined" ? args[key] : match); }); }; } 

也许这可能会更好地处理所有深入的案件,但为了我的需要,这是很好的。

 "This is an example from {name}".format({name:"Blaine"}); "This is an example from {0}".format("Blaine"); 

PS:如果您在AngularJS等模板框架中使用翻译,此function非常酷:

 <h1> {{('hello-message'|translate).format(user)}} <h1> <h1> {{('hello-by-name'|translate).format( user ? user.name : 'You' )}} <h1> 

en.json是类似的东西

 { "hello-message": "Hello {name}, welcome.", "hello-by-name": "Hello {0}, welcome." } 

对于那些喜欢Node.JS及其util.format特性的人来说,我只是把它提取到了它的香草JavaScript表单中(只有util.format使用的函数):

 exports = {}; function isString(arg) { return typeof arg === 'string'; } function isNull(arg) { return arg === null; } function isObject(arg) { return typeof arg === 'object' && arg !== null; } function isBoolean(arg) { return typeof arg === 'boolean'; } function isUndefined(arg) { return arg === void 0; } function stylizeNoColor(str, styleType) { return str; } function stylizeWithColor(str, styleType) { var style = inspect.styles[styleType]; if (style) { return '\u001b[' + inspect.colors[style][0] + 'm' + str + '\u001b[' + inspect.colors[style][3] + 'm'; } else { return str; } } function isFunction(arg) { return typeof arg === 'function'; } function isNumber(arg) { return typeof arg === 'number'; } function isSymbol(arg) { return typeof arg === 'symbol'; } function formatPrimitive(ctx, value) { if (isUndefined(value)) return ctx.stylize('undefined', 'undefined'); if (isString(value)) { var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') .replace(/'/g, "\\'") .replace(/\\"/g, '"') + '\''; return ctx.stylize(simple, 'string'); } if (isNumber(value)) { // Format -0 as '-0'. Strict equality won't distinguish 0 from -0, // so instead we use the fact that 1 / -0 < 0 whereas 1 / 0 > 0 . if (value === 0 && 1 / value < 0) return ctx.stylize('-0', 'number'); return ctx.stylize('' + value, 'number'); } if (isBoolean(value)) return ctx.stylize('' + value, 'boolean'); // For some reason typeof null is "object", so special case here. if (isNull(value)) return ctx.stylize('null', 'null'); // es6 symbol primitive if (isSymbol(value)) return ctx.stylize(value.toString(), 'symbol'); } function arrayToHash(array) { var hash = {}; array.forEach(function (val, idx) { hash[val] = true; }); return hash; } function objectToString(o) { return Object.prototype.toString.call(o); } function isDate(d) { return isObject(d) && objectToString(d) === '[object Date]'; } function isError(e) { return isObject(e) && (objectToString(e) === '[object Error]' || e instanceof Error); } function isRegExp(re) { return isObject(re) && objectToString(re) === '[object RegExp]'; } function formatError(value) { return '[' + Error.prototype.toString.call(value) + ']'; } function formatPrimitiveNoColor(ctx, value) { var stylize = ctx.stylize; ctx.stylize = stylizeNoColor; var str = formatPrimitive(ctx, value); ctx.stylize = stylize; return str; } function isArray(ar) { return Array.isArray(ar); } function hasOwnProperty(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); } function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { var name, str, desc; desc = Object.getOwnPropertyDescriptor(value, key) || {value: value[key]}; if (desc.get) { if (desc.set) { str = ctx.stylize('[Getter/Setter]', 'special'); } else { str = ctx.stylize('[Getter]', 'special'); } } else { if (desc.set) { str = ctx.stylize('[Setter]', 'special'); } } if (!hasOwnProperty(visibleKeys, key)) { name = '[' + key + ']'; } if (!str) { if (ctx.seen.indexOf(desc.value) < 0) { if (isNull(recurseTimes)) { str = formatValue(ctx, desc.value, null); } else { str = formatValue(ctx, desc.value, recurseTimes - 1); } if (str.indexOf('\n') > -1) { if (array) { str = str.split('\n').map(function (line) { return ' ' + line; }).join('\n').substr(2); } else { str = '\n' + str.split('\n').map(function (line) { return ' ' + line; }).join('\n'); } } } else { str = ctx.stylize('[Circular]', 'special'); } } if (isUndefined(name)) { if (array && key.match(/^\d+$/)) { return str; } name = JSON.stringify('' + key); if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { name = name.substr(1, name.length - 2); name = ctx.stylize(name, 'name'); } else { name = name.replace(/'/g, "\\'") .replace(/\\"/g, '"') .replace(/(^"|"$)/g, "'") .replace(/\\\\/g, '\\'); name = ctx.stylize(name, 'string'); } } return name + ': ' + str; } function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { var output = []; for (var i = 0, l = value.length; i < l; ++i) { if (hasOwnProperty(value, String(i))) { output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, String(i), true)); } else { output.push(''); } } keys.forEach(function (key) { if (!key.match(/^\d+$/)) { output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, key, true)); } }); return output; } function reduceToSingleString(output, base, braces) { var length = output.reduce(function (prev, cur) { return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; }, 0); if (length > 60) { return braces[0] + (base === '' ? '' : base + '\n ') + ' ' + output.join(',\n ') + ' ' + braces[1]; } return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; } function formatValue(ctx, value, recurseTimes) { // Provide a hook for user-specified inspect functions. // Check that value is an object with an inspect function on it if (ctx.customInspect && value && isFunction(value.inspect) && // Filter out the util module, it's inspect function is special value.inspect !== exports.inspect && // Also filter out any prototype objects using the circular check. !(value.constructor && value.constructor.prototype === value)) { var ret = value.inspect(recurseTimes, ctx); if (!isString(ret)) { ret = formatValue(ctx, ret, recurseTimes); } return ret; } // Primitive types cannot have properties var primitive = formatPrimitive(ctx, value); if (primitive) { return primitive; } // Look up the keys of the object. var keys = Object.keys(value); var visibleKeys = arrayToHash(keys); if (ctx.showHidden) { keys = Object.getOwnPropertyNames(value); } // This could be a boxed primitive (new String(), etc.), check valueOf() // NOTE: Avoid calling `valueOf` on `Date` instance because it will return // a number which, when object has some additional user-stored `keys`, // will be printed out. var formatted; var raw = value; try { // the .valueOf() call can fail for a multitude of reasons if (!isDate(value)) raw = value.valueOf(); } catch (e) { // ignore... } if (isString(raw)) { // for boxed Strings, we have to remove the 0-n indexed entries, // since they just noisey up the output and are redundant keys = keys.filter(function (key) { return !(key >= 0 && key < raw.length); }); } // Some type of object without properties can be shortcutted. if (keys.length === 0) { if (isFunction(value)) { var name = value.name ? ': ' + value.name : ''; return ctx.stylize('[Function' + name + ']', 'special'); } if (isRegExp(value)) { return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); } if (isDate(value)) { return ctx.stylize(Date.prototype.toString.call(value), 'date'); } if (isError(value)) { return formatError(value); } // now check the `raw` value to handle boxed primitives if (isString(raw)) { formatted = formatPrimitiveNoColor(ctx, raw); return ctx.stylize('[String: ' + formatted + ']', 'string'); } if (isNumber(raw)) { formatted = formatPrimitiveNoColor(ctx, raw); return ctx.stylize('[Number: ' + formatted + ']', 'number'); } if (isBoolean(raw)) { formatted = formatPrimitiveNoColor(ctx, raw); return ctx.stylize('[Boolean: ' + formatted + ']', 'boolean'); } } var base = '', array = false, braces = ['{', '}']; // Make Array say that they are Array if (isArray(value)) { array = true; braces = ['[', ']']; } // Make functions say that they are functions if (isFunction(value)) { var n = value.name ? ': ' + value.name : ''; base = ' [Function' + n + ']'; } // Make RegExps say that they are RegExps if (isRegExp(value)) { base = ' ' + RegExp.prototype.toString.call(value); } // Make dates with properties first say the date if (isDate(value)) { base = ' ' + Date.prototype.toUTCString.call(value); } // Make error with message first say the error if (isError(value)) { base = ' ' + formatError(value); } // Make boxed primitive Strings look like such if (isString(raw)) { formatted = formatPrimitiveNoColor(ctx, raw); base = ' ' + '[String: ' + formatted + ']'; } // Make boxed primitive Numbers look like such if (isNumber(raw)) { formatted = formatPrimitiveNoColor(ctx, raw); base = ' ' + '[Number: ' + formatted + ']'; } // Make boxed primitive Booleans look like such if (isBoolean(raw)) { formatted = formatPrimitiveNoColor(ctx, raw); base = ' ' + '[Boolean: ' + formatted + ']'; } if (keys.length === 0 && (!array || value.length === 0)) { return braces[0] + base + braces[1]; } if (recurseTimes < 0) { if (isRegExp(value)) { return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); } else { return ctx.stylize('[Object]', 'special'); } } ctx.seen.push(value); var output; if (array) { output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); } else { output = keys.map(function (key) { return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); }); } ctx.seen.pop(); return reduceToSingleString(output, base, braces); } function inspect(obj, opts) { // default options var ctx = { seen: [], stylize: stylizeNoColor }; // legacy... if (arguments.length >= 3) ctx.depth = arguments[2]; if (arguments.length >= 4) ctx.colors = arguments[3]; if (isBoolean(opts)) { // legacy... ctx.showHidden = opts; } else if (opts) { // got an "options" object exports._extend(ctx, opts); } // set default options if (isUndefined(ctx.showHidden)) ctx.showHidden = false; if (isUndefined(ctx.depth)) ctx.depth = 2; if (isUndefined(ctx.colors)) ctx.colors = false; if (isUndefined(ctx.customInspect)) ctx.customInspect = true; if (ctx.colors) ctx.stylize = stylizeWithColor; return formatValue(ctx, obj, ctx.depth); } exports.inspect = inspect; // http://en.wikipedia.org/wiki/ANSI_escape_code#graphics inspect.colors = { 'bold': [1, 22], 'italic': [3, 23], 'underline': [4, 24], 'inverse': [7, 27], 'white': [37, 39], 'grey': [90, 39], 'black': [30, 39], 'blue': [34, 39], 'cyan': [36, 39], 'green': [32, 39], 'magenta': [35, 39], 'red': [31, 39], 'yellow': [33, 39] }; // Don't use 'blue' not visible on cmd.exe inspect.styles = { 'special': 'cyan', 'number': 'yellow', 'boolean': 'yellow', 'undefined': 'grey', 'null': 'bold', 'string': 'green', 'symbol': 'green', 'date': 'magenta', // "name": intentionally not styling 'regexp': 'red' }; var formatRegExp = /%[sdj%]/g; exports.format = function (f) { if (!isString(f)) { var objects = []; for (var j = 0; j < arguments.length; j++) { objects.push(inspect(arguments[j])); } return objects.join(' '); } var i = 1; var args = arguments; var len = args.length; var str = String(f).replace(formatRegExp, function (x) { if (x === '%%') return '%'; if (i >= len) return x; switch (x) { case '%s': return String(args[i++]); case '%d': return Number(args[i++]); case '%j': try { return JSON.stringify(args[i++]); } catch (_) { return '[Circular]'; } default: return x; } }); for (var x = args[i]; i < len; x = args[++i]) { if (isNull(x) || !isObject(x)) { str += ' ' + x; } else { str += ' ' + inspect(x); } } return str; }; 

Harvested from: https://github.com/joyent/node/blob/master/lib/util.js

There is "sprintf" for JavaScript which you can find at http://www.webtoolkit.info/javascript-sprintf.html .

I have a slightly longer formatter for JavaScript here …

You can do formatting several ways:

  • String.format(input, args0, arg1, ...)
  • String.format(input, obj)
  • "literal".format(arg0, arg1, ...)
  • "literal".format(obj)

Also, if you have say a ObjectBase.prototype.format (such as with DateJS ) it will use that.

Examples…

 var input = "numbered args ({0}-{1}-{2}-{3})"; console.log(String.format(input, "first", 2, new Date())); //Outputs "numbered args (first-2-Thu May 31 2012...Time)-{3})" console.log(input.format("first", 2, new Date())); //Outputs "numbered args(first-2-Thu May 31 2012...Time)-{3})" console.log(input.format( "object properties ({first}-{second}-{third:yyyy-MM-dd}-{fourth})" ,{ 'first':'first' ,'second':2 ,'third':new Date() //assumes Date.prototype.format method } )); //Outputs "object properties (first-2-2012-05-31-{3})" 

I've also aliased with .asFormat and have some detection in place in case there's already a string.format (such as with MS Ajax Toolkit (I hate that library).

Just in case someone needs a function to prevent polluting global scope, here is the function that does the same:

  function _format (str, arr) { return str.replace(/{(\d+)}/g, function (match, number) { return typeof arr[number] != 'undefined' ? arr[number] : match; }); }; 

For basic formatting:

 var template = jQuery.validator.format("{0} is not a valid value"); var result = template("abc"); 

I did not see the String.format variant:

 String.format = function (string) { var args = Array.prototype.slice.call(arguments, 1, arguments.length); return string.replace(/{(\d+)}/g, function (match, number) { return typeof args[number] != "undefined" ? args[number] : match; }); }; 

I didn't see pyformat in the list so I thought I'd throw it in:

 console.log(pyformat( 'The {} {} jumped over the {}' , ['brown' ,'fox' ,'foobar'] )) console.log(pyformat('The {0} {1} jumped over the {1}' , ['brown' ,'fox' ,'foobar'] )) console.log(pyformat('The {color} {animal} jumped over the {thing}' , [] ,{color: 'brown' ,animal: 'fox' ,thing: 'foobaz'} )) 
 /** * Format string by replacing placeholders with value from element with * corresponsing index in `replacementArray`. * Replaces are made simultaneously, so that replacement values like * '{1}' will not mess up the function. * * Example 1: * ('{2} {1} {0}', ['three', 'two' ,'one']) -> 'one two three' * * Example 2: * ('{0}{1}', ['{1}', '{0}']) -> '{1}{0}' */ function stringFormat(formatString, replacementArray) { return formatString.replace( /\{(\d+)\}/g, // Matches placeholders, eg '{1}' function formatStringReplacer(match, placeholderIndex) { // Convert String to Number placeholderIndex = Number(placeholderIndex); // Make sure that index is within replacement array bounds if (placeholderIndex < 0 || placeholderIndex > replacementArray.length - 1 ) { return placeholderIndex; } // Replace placeholder with value from replacement array return replacementArray[placeholderIndex]; } ); }