JavaScript equivalent to printf/String.Format
JavaScript equivalent to printf/String.Format
Question
I'm looking for a good JavaScript equivalent of the C/PHP printf()
or for C#/Java programmers, String.Format()
(IFormatProvider
for .NET).
My basic requirement is a thousand separator format for numbers for now, but something that handles lots of combinations (including dates) would be good.
I realize Microsoft's Ajax library provides a version of String.Format()
, but we don't want the entire overhead of that framework.
Accepted Answer
From ES6 on you could use template strings:
let soMany = 10;
console.log(`This is ${soMany} times easier!`);
// "This is 10 times easier!
See Kim's answer below for details.
Otherwise:
If you really want to do a simple format method on your own, don’t do the replacements successively but do them simultaneously.
Because most of the other proposals that are mentioned fail when a replace string of previous replacement does also contain a format sequence like this:
"{0}{1}".format("{1}", "{0}")
Normally you would expect the output to be {1}{0}
but the actual output is {1}{1}
. So do a simultaneously replacement instead like in fearphage’s suggestion.
Popular Answer
Building on the previously suggested solutions:
// 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")
outputs
ASP is dead, but ASP.NET is alive! ASP {2}
If you prefer not to modify String
's prototype:
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
;
});
};
}
Gives you the much more familiar:
String.format('{0} is dead, but {1} is alive! {0} {2}', 'ASP', 'ASP.NET');
with the same result:
ASP is dead, but ASP.NET is alive! ASP {2}
Read more… Read less…
It's funny because Stack Overflow actually has their own formatting function for the String
prototype called formatUnicorn
. Try it! Go into the console and type something like:
"Hello, {name}, are you feeling {adjective}?".formatUnicorn({name:"Gabriel", adjective: "OK"});
You get this output:
Hello, Gabriel, are you feeling OK?
You can use objects, arrays, and strings as arguments! I got its code and reworked it to produce a new version of 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;
};
Note the clever Array.prototype.slice.call(arguments)
call -- that means if you throw in arguments that are strings or numbers, not a single JSON-style object, you get C#'s String.Format
behavior almost exactly.
"a{0}bcd{1}ef".formatUnicorn("foo", "bar"); // yields "aFOObcdBARef"
That's because Array
's slice
will force whatever's in arguments
into an Array
, whether it was originally or not, and the key
will be the index (0, 1, 2...) of each array element coerced into a string (eg, "0", so "\\{0\\}"
for your first regexp pattern).
Neat.
Number Formatting in JavaScript
I got to this question page hoping to find how to format numbers in JavaScript, without introducing yet another library. Here's what I've found:
Rounding floating-point numbers
The equivalent of sprintf("%.2f", num)
in JavaScript seems to be num.toFixed(2)
, which formats num
to 2 decimal places, with rounding (but see @ars265's comment about Math.round
below).
(12.345).toFixed(2); // returns "12.35" (rounding!)
(12.3).toFixed(2); // returns "12.30" (zero padding)
Exponential form
The equivalent of sprintf("%.2e", num)
is num.toExponential(2)
.
(33333).toExponential(2); // "3.33e+4"
Hexadecimal and other bases
To print numbers in base B, try num.toString(B)
. JavaScript supports automatic conversion to and from bases 2 through 36 (in addition, some browsers have limited support for base64 encoding).
(3735928559).toString(16); // to base 16: "deadbeef"
parseInt("deadbeef", 16); // from base 16: 3735928559
Reference Pages
Quick tutorial on JS number formatting
Mozilla reference page for toFixed() (with links to toPrecision(), toExponential(), toLocaleString(), ...)
From ES6 on you could use template strings:
let soMany = 10;
console.log(`This is ${soMany} times easier!`);
// "This is 10 times easier!
Be aware that template strings are surrounded by backticks ` instead of (single) quotes.
For further information:
https://developers.google.com/web/updates/2015/01/ES6-Template-Strings
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/template_strings
Note: Check the mozilla-site to find a list of supported browsers.
jsxt, Zippo
This option fits better.
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;
};
With this option I can replace strings like these:
'The {0} is dead. Don\'t code {0}. Code {1} that is open source!'.format('ASP', 'PHP');
With your code the second {0} wouldn't be replaced. ;)
I use this simple function:
String.prototype.format = function() {
var formatted = this;
for( var arg in arguments ) {
formatted = formatted.replace("{" + arg + "}", arguments[arg]);
}
return formatted;
};
That's very similar to string.format:
"{0} is dead, but {1} is alive!".format("ASP", "ASP.NET")