6

I know that console.log supports at least some of the basic features of printf from C through messing around, but I was curious of a way to take advantage of console.log's implementation to create something similar to sprintf. I know you can't simply use .bind or .apply since console.log doesn't actually return the string, so is there a way around this?

If this isn't actually possible, is there some other little-known native implementation that's only a few lines of code away from achieving sprintf in JavaScript?

For those who do not know what sprintf is exactly, here is some documentation from tutorialspoint. Example usage I'm looking for is below:

var string1 = sprintf("Hello, %s!", "world");
var string2 = sprintf("The answer to everything is %d.", 42);
1
  • I found the implementation of console.log github.com/joyent/node/blob/master/lib/console.js there doesn't seem to be a way to insert code inbetween anywhere. Best bet would be copy over the format function and build the string your self. Commented Jun 25, 2015 at 2:50

2 Answers 2

7

Keep it simple

var sprintf = (str, ...argv) => !argv.length ? str : 
    sprintf(str = str.replace(sprintf.token||"$", argv.shift()), ...argv);

Since Javascript handles data types automatically, there is no need for type options.

If you need padding, "15".padStart(5,"0") = ("00000"+15).slice(-5) = "00015".

Usage

var sprintf = (str, ...argv) => !argv.length ? str : 
    sprintf(str = str.replace(sprintf.token||"$", argv.shift()), ...argv);

alert(sprintf("Success after $ clicks ($ seconds).", 15, 4.569));
sprintf.token = "_";
alert(sprintf("Failure after _ clicks (_ seconds).", 5, 1.569));

sprintf.token = "%";
var a = "%<br>%<br>%";
var b = sprintf("% plus % is %", 0, 1, 0 + 1);
var c = sprintf("Hello, %!", "world");
var d = sprintf("The answer to everything is %.", 42);
document.write(sprintf(a,b,c,d));

Sign up to request clarification or add additional context in comments.

1 Comment

I do like the convention of $ as placeholders, especially since typing is not really strictly necessary in string templating. Thank you for this simple idea.
3

Try utilizing eval , .replace

var sprintf = function sprintf() {
  // arguments
  var args = Array.prototype.slice.call(arguments)
    // parameters for string
  , n = args.slice(1, -1)
    // string
  , text = args[0]
    // check for `Number`
  , _res = isNaN(parseInt(args[args.length - 1])) 
             ? args[args.length - 1] 
               // alternatively, if string passed
               // as last argument to `sprintf`,
               // `eval(args[args.length - 1])`
             : Number(args[args.length - 1]) 
    // array of replacement values
  , arr = n.concat(_res)
    // `res`: `text`
  , res = text;
  // loop `arr` items
  for (var i = 0; i < arr.length; i++) {
    // replace formatted characters within `res` with `arr` at index `i`
    res = res.replace(/%d|%s/, arr[i])
  }
  // return string `res`
  return res
};

document.write(sprintf("%d plus %d is %d", 0, 1, 0 + 1) 
               + "<br>" 
               + sprintf("Hello, %s!", "world") 
               + "<br>" 
               + sprintf("The answer to everything is %d.", 42)
              );

2 Comments

That looks neat, but I'm not sure why you have eval in there... why can't you just use parseInt again?
@PatrickRoberts eval was utilized to evaluate string "0+1" ; updated post passes mathematical expression as Number, + operator rather than String input to avoid using eval. Another option at that portion of sprintf function could possibly utilize Function .

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.