JavaScript printf
Output a formatted string
1 2 3 4 56 7 8 9 1011 12 13 14 1516 17 18 19 2021 22 23 24 2526 27 28 29 3031 32 | function printf () { // Output a formatted string // // version: 1008.1718 // discuss at: http://phpjs.org/functions/printf // + original by: Ash Searle (http://hexmen.com/blog/) // + improved by: Michael White (http://getsprink.com) // + improved by: Brett Zamir (http://brett-zamir.me) // - depends on: sprintf // * example 1: printf("%01.2f", 123.1); // * returns 1: 6 var body, elmt, d = this.window.document; var ret = ''; var HTMLNS = 'http://www.w3.org/1999/xhtml'; body = d.getElementsByTagNameNS ? (d.getElementsByTagNameNS(HTMLNS, 'body')[0] ? d.getElementsByTagNameNS(HTMLNS, 'body')[0] : d.documentElement.lastChild) : d.getElementsByTagName('body')[0]; if (!body) { return false; } ret = this.sprintf.apply(this, arguments); elmt = d.createTextNode(ret); body.appendChild(elmt); return ret.length; } |
Examples
Running
1 | printf("%01.2f", 123.1); |
Should return
1 | 6 |
Dependencies
In order to use this function, you also need:
Open syntax issues
php.js uses JsLint to help us keep our code consistent and prevent some common bugs.
Eventually we want all code to pass or at least take into consideration most fixes suggested by JsLint, following this JsLint configuration we’ve decided on.
Authors
Thanks to the following developers, you get to have printf goodness in JavaScript.
Had a slight bug in this line (for vprintf and printf):
[CODE="Javascript"]
body = document.getElementsByTagNameNS ?
(document.getElementsByTagNameNS(HTMLNS, 'body')[0] ?
document.getElementsByTagNameNS(HTMLNS, 'body')[0] :
document.documentElement.lastChild) :
document.getElementsByTagName('body')[0];
[/CODE]
Here's vprintf based largely on printf (and helped a little by vsprintf).
I think the lines in printf dealing with setting up body should also allow (as does my vprintf below) for getElementsByTagNameNS if available or the last child of the XML document if body is not available (allows this function to work in XUL, etc.):
[CODE="Javascript"]
var HTMLNS = 'http://www.w3.org/1999/xhtml';
body = document.getElementsByTagNameNS ?
(document.getElementsByTagNameNS(HTMLNS, 'body')[0] ?
document.getElementsByTagNameNS(HTMLNS, 'body') :
document.documentElement.lastChild) :
document.getElementsByTagName('body')[0];
if (!body) {
return false;
}[/CODE]
If that is done the declaration "bodies = [], " can also be removed.
[CODE="Javascript"]
function vprintf(format, args) {
// http://kevin.vanzonneveld.net
// + original by: Ash Searle (http://hexmen.com/blog/)
// + improved by: Michael White (http://getsprink.com)
// - depends on: sprintf
// * example 1: printf("%01.2f", 123.1);
// * returns 1: 6
var body, elmt;
var ret = '';
// .shift() does not work to get first item in bodies
var HTMLNS = 'http://www.w3.org/1999/xhtml';
body = document.getElementsByTagNameNS ?
(document.getElementsByTagNameNS(HTMLNS, 'body')[0] ?
document.getElementsByTagNameNS(HTMLNS, 'body') :
document.documentElement.lastChild) :
document.getElementsByTagName('body')[0];
if (!body) {
return false;
}
ret = sprintf.apply(this, [format].concat(args));
elmt = document.createTextNode(ret);
body.appendChild(elmt);
return ret.length;
}[/CODE]
@ Michael White: two of them were related to flawed examples of my own ;) but i think there is still some discrepancies between include & require ?
@ Michael White: LOL :) No problem dude. Thanks for all of the hard work. There still are some errors though: http://kevin.vanzonneveld.net/pj_tester.php
Ok, I swear this is my last post tonight. I've just been really busy working on a few things that happen to really coincide with what is being done here with php.js
[CODE="Javascript"]
// This post doesn't have code - just a URL.
// Use the URL in this post to find a source file with a few new functions and some updates to existing functions. It also contains updates to a couple of my own new functions that I have already posted and then found some little discrepancies in.
// http://www.sprinkit.net/aether/php_js-updates.js
Maybe in the future I will just save all my work on php.js stuff into a single file and post it all at once so this doesn't happen again.
[/CODE]
floatval() : A nearly pointless addition. Only slightly more than a wrapper for JavaScript's parseFloat() method.
[CODE="Javascript"]
function floatval(mixed_var) {
// * example 1: floatval('150.03_page-section');
// * return 1: 150.03
// * example 2: floatval('page: 3');
// * return 2: 0
// * example 2: floatval('-50 + 8');
// * return 2: -50
// Note: The native parseFloat() method of JavaScript returns NaN when it encounters a string before an int or float value.
return (parseFloat(mixed_var) || 0);
}
[/CODE]
http://crestidg.com
I ended up nearly rewriting this function...
[CODE="Javascript"]
function printf( ) {
// * example 1: printf("%01.2f", 123.1);
// * returns 1: 6
var ret = this.sprintf.apply(this, arguments);
document.write(ret);
return ret.length;
}
[/CODE]
The previous code turned the arguments array into a string representation of that array. With eval() that works properly but with apply() it expects the arguments to be an array. All we have to do is leave the arguments array alone and pass it directly to the apply() function call. The "this" keyword makes sure the proper scope is used and applied to the function whether the code is namespaced or just in the global namespace as a simple function. Why it worked in a namespace when passing string arguments I cannot pretend to know.... but at least it works everywhere now.
Hmm - not sure I can grab that OS but I'll see if I can get the error on another OS. The good news is that I have a new function: print_r()
[CODE="Javascript"]
function print_r(array, return_val) {
var output = "", pad_char = " ", pad_val = 3;
function formatArray(obj, cur_depth, pad_val, pad_char) {
if(cur_depth > 0)
cur_depth++;
var base_pad = repeat_char(pad_val*cur_depth, pad_char);
var thick_pad = repeat_char(pad_val*(cur_depth+1), pad_char);
var str = "";
if(obj instanceof Array) {
str += "Array\n" + base_pad + "(\n";
for(var key in obj) {
if(obj[key] instanceof Array) {
str += thick_pad + "["+key+"] => "+formatArray(obj[key], cur_depth+1, pad_val, pad_char);
} else {
str += thick_pad + "["+key+"] => " + obj[key] + "\n";
}
}
str += base_pad + ")\n";
} else {
str = obj.toString(); // They didn't pass in an array.... why? -- Do the best we can to output this object.
};
return str;
};
function repeat_char(len, char) {
var str = "";
for(var i=0; i < len; i++) { str += char; };
return str;
};
output = formatArray(array, 0, pad_val, pad_char);
if(return_val !== true) {
document.write("<pre>" + output + "</pre>");
} else {
return output;
}
}
The <pre> tags here are optional for the version you release (although they are recommended) I like them because unless you have Firefox you probably can't view "generated source" and you won't be able to make sense of the data unless it is formatted.
http://crestidg.com -- by the way - how do I add line breaks in this message box?
[/CODE]
What browser(s)? I think I have a solution anyway and I'm going to test it as soon as I can obtain that error message.
Michael White: I agree that that would be better but it currently generates a: 'format has no properties' error on the line with:
[CODE="Javascript"]
return format.replace(regex, function(substring, valueIndex, flags, minWidth, _, precision, type) {
[/CODE]
This function can be made a bit more flexible by not using the eval() function. This really helps more when using namespaces to encapsulate the code. Line three in the example shows the line I used when inside a closed namespace.
[CODE="Javascript"]
//ret = eval('sprintf(' + args + ')'); // Old
ret = sprintf.apply(this, args); // New
//ret = this.sprintf.apply(this, args); // When inside a closed namespace.
[/CODE]
http://crestidg.com


Kevin van Zonneveld
1 Feb '09