better support for floating point precision (closes #6)

This commit is contained in:
Sami Samhuri 2014-10-17 14:55:43 -07:00
parent 7f14e8bb68
commit 35d4cf5f4f
5 changed files with 64 additions and 19 deletions

View file

@ -35,11 +35,12 @@ Supported format specifiers: b, c, d, f, o, s, x, and X.
See `man 3 printf` or `man 1 printf` for details. See `man 3 printf` or `man 1 printf` for details.
Precision is supported for floating point numbers.
License License
======= =======
Copyright 2010 - 2013 Sami Samhuri sami@samhuri.net Copyright 2010 - 2014 Sami Samhuri sami@samhuri.net
[MIT license](http://sjs.mit-license.org) [MIT license](http://sjs.mit-license.org)

View file

@ -3,7 +3,7 @@
"repo": "samsonjs/format", "repo": "samsonjs/format",
"description": "printf, sprintf, and vsprintf for JavaScript", "description": "printf, sprintf, and vsprintf for JavaScript",
"keywords": ["format", "printf", "sprintf", "vsprintf", "string"], "keywords": ["format", "printf", "sprintf", "vsprintf", "string"],
"version": "0.2.1", "version": "0.2.2",
"main": "format.js", "main": "format.js",
"scripts": ["format.js"] "scripts": ["format.js"]
} }

View file

@ -49,12 +49,16 @@
, c , c
, escaped = false , escaped = false
, arg , arg
, tmp
, leadingZero = false
, precision , precision
, nextArg = function() { return args[argIndex++]; } , nextArg = function() { return args[argIndex++]; }
, slurpNumber = function() { , slurpNumber = function() {
var digits = ''; var digits = '';
while (fmt[i].match(/\d/)) while (/\d/.test(fmt[i])) {
digits += fmt[i++]; digits += fmt[i++];
c = fmt[i];
}
return digits.length > 0 ? parseInt(digits) : null; return digits.length > 0 ? parseInt(digits) : null;
} }
; ;
@ -62,6 +66,18 @@
c = fmt[i]; c = fmt[i];
if (escaped) { if (escaped) {
escaped = false; escaped = false;
if (c == '.') {
leadingZero = false;
c = fmt[++i];
}
else if (c == '0' && fmt[i + 1] == '.') {
leadingZero = true;
i += 2;
c = fmt[i];
}
else {
leadingZero = true;
}
precision = slurpNumber(); precision = slurpNumber();
switch (c) { switch (c) {
case 'b': // number in binary case 'b': // number in binary
@ -78,7 +94,8 @@
result += parseInt(nextArg(), 10); result += parseInt(nextArg(), 10);
break; break;
case 'f': // floating point number case 'f': // floating point number
result += parseFloat(nextArg()).toFixed(precision || 6); tmp = String(parseFloat(nextArg()).toFixed(precision || 6));
result += leadingZero ? tmp : tmp.replace(/^0/, '');
break; break;
case 'o': // number in octal case 'o': // number in octal
result += '0' + parseInt(nextArg(), 10).toString(8); result += '0' + parseInt(nextArg(), 10).toString(8);

View file

@ -1,7 +1,7 @@
{ {
"name": "format", "name": "format",
"description": "printf, sprintf, and vsprintf for JavaScript", "description": "printf, sprintf, and vsprintf for JavaScript",
"version": "0.2.1", "version": "0.2.2",
"homepage": "http://samhuri.net/proj/format", "homepage": "http://samhuri.net/proj/format",
"author": "Sami Samhuri <sami@samhuri.net>", "author": "Sami Samhuri <sami@samhuri.net>",
"repository": { "repository": {

View file

@ -3,23 +3,50 @@ var filename = process.argv[2] || './format.js'
, printf = format.printf , printf = format.printf
; ;
console.log('Testing printf:'); function desc(x, indentLevel) {
printf('hello'); indentLevel = indentLevel || 0;
console.log('(expected "hello")'); var indent = new Array(indentLevel).join(' ');
printf('hello %s', 'sami'); if (typeof x == 'string' || (x && x.__proto__ == String.prototype)) {
console.log('(expected "hello sami")'); return indent + '"' + x + '"';
printf('b: %b\nc: %c\nd: %d\nf: %f\no: %o\ns: %s\nx: %x\nX: %X', 42, 65, 42*42, 42*42*42/1000000000, 255, 'sami', 0xfeedface, 0xc0ffee); }
console.log('(expected "b: 101010\nc: A\nd: 1764\nf: 0.000074\no: 0377\ns: sami\nx: 0xfeedface\nX: 0xC0FFEE")'); else if (Array.isArray(x)) {
console.log('(passed if the output looks ok)'); return indent + '[ ' + x.map(desc).join(', ') + ' ]';
}
else {
return '' + x;
}
}
function assertEqual(a, b) { function assertFormat(args, expected) {
if (a !== b) throw new Error('assertion failed, ' + a + ' !== ' + b); var fmt = args[0];
var result = format.format.apply(format, args);
if (result !== expected) {
console.log('FORMAT: "' + fmt + '"');
console.log('ARGS: ' + desc(args.slice(1)));
console.log('RESULT: "' + result + '"');
throw new Error('assertion failed, ' + result + ' !== ' + expected);
}
} }
console.log('Testing format:'); console.log('Testing format:');
assertEqual(format.format('hello'), 'hello');
assertEqual(format.format('hello %s', 'sami'), 'hello sami'); var tests = [
assertEqual(format.format('b: %b\nc: %c\nd: %d\nf: %f\no: %o\ns: %s\nx: %x\nX: %X', 42, 65, 42*42, 42*42*42/1000000000, 255, 'sami', 0xfeedface, 0xc0ffee), "b: 101010\nc: A\nd: 1764\nf: 0.000074\no: 0377\ns: sami\nx: 0xfeedface\nX: 0xC0FFEE"); [['hello'], 'hello'],
console.log('(pass)'); [['hello %s', 'sami'], 'hello sami'],
[
['b: %b\nc: %c\nd: %d\nf: %f\no: %o\ns: %s\nx: %x\nX: %X', 42, 65, 42*42, 42*42*42/1000000000, 255, 'sami', 0xfeedface, 0xc0ffee],
"b: 101010\nc: A\nd: 1764\nf: 0.000074\no: 0377\ns: sami\nx: 0xfeedface\nX: 0xC0FFEE"
],
[['%.2f', 3.14159], '3.14'],
[['%0.2f', 3.14159], '3.14'],
[['%.2f', 0.1234], '.12'],
[['%0.2f', 0.1234], '0.12']
];
tests.forEach(function(spec) {
var args = spec[0];
var expected = spec[1];
assertFormat(args, expected);
console.log('pass (format ' + args[0] + ' == ' + expected + ')');
});
console.log('all passed'); console.log('all passed');