diff --git a/js/misc/format.js b/js/misc/format.js index 792d306a7..dcebf7e68 100644 --- a/js/misc/format.js +++ b/js/misc/format.js @@ -6,8 +6,10 @@ * It has to be set up using String.prototype.format = Format.format; * Usage: * "somestring %s %d".format('hello', 5); - * It supports %s, %d and %f, for %f it also support precisions like - * "%.2f".format(1.526) + * It supports %s, %d, %x and %f, for %f it also support precisions like + * "%.2f".format(1.526). All specifiers can be prefixed with a minimum + * field width, e.g. "%5s".format("foo"). Unless the width is prefixed + * with '0', the formatted string will be padded with spaces. */ function format() { @@ -15,30 +17,44 @@ function format() { let i = 0; let args = arguments; - return str.replace(/%(?:\.([0-9]+))?(.)/g, function (str, precisionGroup, genericGroup) { + return str.replace(/%([0-9]+)?(?:\.([0-9]+))?(.)/g, function (str, widthGroup, precisionGroup, genericGroup) { if (precisionGroup != '' && genericGroup != 'f') throw new Error("Precision can only be specified for 'f'"); + let fillChar = (widthGroup[0] == '0') ? '0' : ' '; + let width = parseInt(widthGroup, 10) || 0; + + function fillWidth(s, c, w) { + let fill = ''; + for (let i = 0; i < w; i++) + fill += c; + return fill.substr(s.length) + s; + } + + let s = ''; switch (genericGroup) { case '%': return '%'; break; case 's': - return args[i++].toString(); + s = args[i++].toString(); break; case 'd': - return parseInt(args[i++]); + s = parseInt(args[i++]).toString(); + break; + case 'x': + s = parseInt(args[i++]).toString(16); break; case 'f': if (precisionGroup == '') - return parseFloat(args[i++]); + s = parseFloat(args[i++]).toString(); else - return parseFloat(args[i++]).toFixed(parseInt(precisionGroup)); + s = parseFloat(args[i++]).toFixed(parseInt(precisionGroup)); break; default: throw new Error('Unsupported conversion character %' + genericGroup); } - return ""; // Suppress warning + return fillWidth(s, fillChar, width); }); } diff --git a/tests/unit/format.js b/tests/unit/format.js index 9e618c27b..80ada20e8 100644 --- a/tests/unit/format.js +++ b/tests/unit/format.js @@ -20,8 +20,15 @@ assertEquals("%s", "%%s".format('foo')); assertEquals("%%s", "%%%%s".format('foo')); assertEquals("foo 5", "%s %d".format('foo', 5)); assertEquals("8", "%d".format(8)); +assertEquals("f", "%x".format(15)); assertEquals("2.58 6.96", "%f %.2f".format(2.58, 6.958)); +// Test field width +assertEquals("007 foo", "%03d %4s".format(7, 'foo')); +assertEquals(" 2.58 06.96", "%5f %05.2f".format(2.58, 6.958)); +assertEquals("cafe", "%2x".format(0xcafe)); +assertEquals("foo", "%0s".format('foo')); + // Precision is only allowed for %f assertRaises(function() { "%.2d".format(5.21) });