8

Browsers such as Chrome and Firefox offer a console API that enable the emission of formatted log messages, like this:

>>> console.log("%s has %d points", "Sam", "100");
Sam has 100 points

Now, suppose I want to generate a formatted string but not necessarily log it into the console. Do the browsers expose the native function that produces the log strings? Is it ECMA-stardard? Or should we be content with third party libraries such as JavaScript sprintf for now?

3
  • No native yet, but here's a library - diveintojavascript.com/projects/javascript-sprintf Commented Apr 4, 2013 at 18:52
  • @Ian Yes! It's mentioned in the question. That lib is impressive. Commented Apr 4, 2013 at 18:53
  • Holy crap, I'm an idiot. Haha I didn't even notice it in the question, sorry about that. The link's text is dull because I've visited it before, so it blended in with the other text (and I clearly didn't read your question fully) :( Commented Apr 4, 2013 at 18:54

3 Answers 3

6
Object.defineProperty(String.prototype, "printf",
        {
            value: function()
                {
                    var args = Array.from(arguments), i = 0;
                    function defaultNumber(iValue)
                    {
                        return ((iValue != undefined) && !isNaN(iValue) ? iValue: "0");
                    }
                    function defaultString(iValue)
                    {
                        return (iValue == undefined? "": "" + iValue);
                    }
                    return this.replace(/%%|%([+\-])?([^1-9])?(\d+)?(\.\d+)?([deEfhHioQqs])/g,
                        function (match, sign, filler, scale, precision, type)
                            {
                                var strOut, space, value;
                                var asNumber = false;
                                if (match == "%%")
                                    return "%";
                                if (i >= args.length)
                                    return match;
                                value = args[i];
                                while (Array.isArray(value))
                                {
                                    args.splice(i, 1);
                                    for (var j = i; value.length > 0; j++)
                                        args.splice(j, 0, value.shift());
                                    value = args[i];
                                }
                                i++;
                                if (filler == undefined)
                                    filler = " "; // default
                                if ((scale == undefined) && !isNaN(filler))
                                {
                                    scale = filler;
                                    filler = " ";
                                }
                                if (sign == undefined) sign = ("sqQ".indexOf(type) >= 0? "+": "-"); // default
                                if (scale == undefined) scale = 0; // default
                                if (precision == undefined) precision = ".0"; // default
                                scale = parseInt(scale);
                                precision = parseInt(precision.substr(1));
                                switch (type)
                                {
                                    case 'd':
                                    case 'i':
                                        // decimal integer
                                        asNumber = true;
                                        strOut = parseInt(defaultNumber(value));
                                        if (precision > 0)
                                            strOut += "." + "0".repeat(precision);
                                        break;
                                    case 'e':
                                    case 'E':
                                        // float in exponential notation
                                        asNumber = true;
                                        strOut = parseFloat(defaultNumber(value));
                                        if (precision == 0)
                                            strOut = strOut.toExponential();
                                        else
                                            strOut = strOut.toExponential(precision);
                                        if (type == 'E')
                                            strOut = strOut.replace('e', 'E');
                                        break;
                                    case 'f':
                                        // decimal float
                                        asNumber = true;
                                        strOut = parseFloat(defaultNumber(value));
                                        if (precision != 0)
                                            strOut = strOut.toFixed(precision);
                                        break;
                                    case 'o':
                                    case 'h':
                                    case 'H':
                                        // Octal or Hexagesimal integer notation
                                        strOut = '\\' + (type == 'o'? '0': type) +
                                            parseInt(defaultNumber(value)).toString((type == 'o'? 8: 16));
                                        break;
                                    case'q':
                                        // single quoted string
                                        strOut = "'" + defaultString(value) + "'";
                                        break;
                                    case'Q':
                                        // double quoted string
                                        strOut = '"' + defaultString(value) + '"';
                                        break;
                                    default:
                                        // string
                                        strOut = defaultString(value);
                                        break;
                                }
                                if (typeof strOut != "string")
                                    strOut = ("" + strOut);
                                if ((space = strOut.length) < scale)
                                {
                                    if (asNumber)
                                    {
                                        if (sign == "-")
                                        {
                                            if (strOut.indexOf('-') < 0)
                                                strOut = filler.repeat(scale - space) + strOut;
                                            else
                                                strOut = '-' + filler.repeat(scale - space) + strOut.replace("-","");
                                        }
                                        else
                                        {
                                            if (strOut.indexOf('-') < 0)
                                                strOut = '+' + filler.repeat(scale - space - 1) + strOut;
                                            else
                                                strOut = '-' + filler.repeat(scale - space) + strOut.replace("-","");
                                        }
                                    }
                                    else
                                    {
                                        if (sign == "-")
                                            strOut = filler.repeat(scale - space) + strOut;
                                        else
                                            strOut = strOut + filler.repeat(scale - space);
                                    }
                                }
                                else if (asNumber && (sign == '+') && (strOut.indexOf('-') < 0))
                                    strOut = '+' + strOut;
                                return strOut;
                            });
                }
        });

    Object.defineProperty(window, "printf",
        {
            value: function(str, ...rest)
            {
                if (typeof str == "string")
                    return String.prototype.printf.apply(str,rest);
                return "";
            }
        });
printf("Your Name is:%_30s your age is: %o\nyour wish is: %20q;", "Tom Johnson",48,"Lotto Numbers");

yields:

"Your Name is:Tom Johnson___________________ your age is: \\060
your wish is: 'Lotto Numbers'     ;"

You can also call it with:

"Your Name is:%_30s your age is: %o\nyour wish is: %20q;".printf("Tom Johnson",48,"Lotto Numbers");
Sign up to request clarification or add additional context in comments.

1 Comment

Good work! Best answer by far.
4

ES6 will introduce some basic string formatting in the form of:

`${name} has ${val} points`;

But there's currently no native string formatting in ES5.

2 Comments

this is not really similiar to printf, name and val in this case should be define
This is not a printf like function
-4

I don't think you can do it natively. You can write your own javascript toString function to handle the different options.

Alternatively you could do

var samuel = "sam";
var someNumber = 100;

var someString = samuel + " has " + someNumber + " points";

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.