JavaScript equivalent of Python's format() function?

前端 未结 17 1981
慢半拍i
慢半拍i 2020-12-13 08:42

Python has this beautiful function to turn this:

bar1 = \'foobar\'
bar2 = \'jumped\'
bar3 = \'dog\'

foo = \'The lazy \' + bar3 + \' \' + bar2 \' over the \'         


        
相关标签:
17条回答
  • 2020-12-13 08:52
    String.prototype.format = function () {
        var i=0,args=arguments,formats={
            "f":(v,s,c,f)=>{s=s||' ',c=parseInt(c||'0'),f=parseInt(f||'-1');v=f>0?Math.floor(v).toString()+"."+Math.ceil(v*Math.pow(10,f)).toString().slice(-f):(f==-1?v.toString():Math.floor(v).toString());return c>v.length?s.repeat(c-v.length)+v:v;},
            "d":(v,s,c,f)=>{s=s||' ',c=parseInt(c||'0');v=Math.floor(v).toString();return c>v.length?s.repeat(c-v.length)+v:v;},
            "s":(v,s,c,f)=>{s=s||' ',c=parseInt(c||'0');return c>v.length?s.repeat(c-v.length)+v:v;},
            "x":(v,s,c,f)=>{s=s||' ',c=parseInt(c||'0');v=Math.floor(v).toString(16);return c>v.length?s.repeat(c-v.length)+v:v;},
            "X":(v,s,c,f)=>{s=s||' ',c=parseInt(c||'0');v=Math.floor(v).toString(16).toUpperCase();return c>v.length?s.repeat(c-v.length)+v:v;},
        };
        return this.replace(/{(\d+)?:?([0=-_*])?(\d+)?\.?(\d+)?([dfsxX])}/g, function () {
            let pos = arguments[1]||i;i++;
            return typeof args[pos] != 'undefined' ? formats[arguments[5]](args[pos],arguments[2],arguments[3],arguments[4]) : '';
        });
    };
    
    0 讨论(0)
  • 2020-12-13 08:54

    Looking for an answer for the same question, I just found this: https://github.com/davidchambers/string-format, which is "JavaScript string formatting inspired by Python’s str.format()". It seem it's pretty much the same as python's format() function.

    0 讨论(0)
  • 2020-12-13 08:55

    tl;dr

    foo = (a, b, c) => `The lazy ${a} ${b} over the ${c}`
    

    Why template strings alone aren't enough

    ES6 template strings provide a feature quite similar to pythons string format. However, you have to know the variables before you construct the string:

    var templateString = `The lazy ${bar3} ${bar2} over the ${bar1}`;
    

    Why format?

    Python's str.format allows you to specify the string before you even know which values you want to plug into it, like:

    foo = 'The lazy {} {} over the {}'
    
    bar1 = 'foobar'
    bar2 = 'jumped'
    bar3 = 'dog'
    
    foo.format(bar3, bar2, bar1)
    

    Solution

    With an arrow function, we can elegantly wrap the template string for later use:

    foo = (a, b, c) => `The lazy ${a} ${b} over the ${c}`
    
    bar1 = 'foobar';
    bar2 = 'jumped';
    bar3 = 'dog';
    
    foo(bar3, bar2, bar1)
    

    Of course this works with a regular function as well, but the arrow function allows us to make this a one-liner. Both features are available in most browsers und runtimes:

    • Can I use template literals?
    • Can I use arrow functions?
    0 讨论(0)
  • 2020-12-13 08:55

    Here's my first attempt. Feel free to point out flaws.

    Example: http://jsfiddle.net/wFb2p/5/

    String.prototype.format = function() {
        var str = this;
        var i = 0;
        var len = arguments.length;
        var matches = str.match(/{}/g);
        if( !matches || matches.length !== len ) {
            throw "wrong number of arguments";
        }
        while( i < len ) {
            str = str.replace(/{}/, arguments[i] );
            i++;
        }
        return str;
    };
    

    EDIT: Made it a bit more efficient by eliminating the .match() call in the while statement.

    EDIT: Changed it so that the same error is thrown if you don't pass any arguments.

    0 讨论(0)
  • 2020-12-13 08:56

    If you (like me) only need the limited subset of python's format function for simple string replacement, and performance is not critical, a very simple 29-line pure-Javascript function may suffice.

    Javascript call: format(str, data)

    Analogous python call: str.format(**data), with the caveat that this javascript function, unlike Python's, does not throw an error if the string contains a varname that is not found in the provided data.

    /*
     * format(str, data): analogous to Python's str.format(**data)
     *
     * Example:
     *   let data = {
     *     user: {
     *       name: { first: 'Jane', last: 'Doe' }
     *     },
     *     email: 'jane@doe.com',
     *     groups: ["one","two"]
     *   };
     *
     *   let str = 'Hi {user.name.first} {user.name.last}, your email address is {email}, and your second group is {groups[1]}'
     * 
     *   format(str, data)
     *   => returns "Hi Jane Doe, your email address is jane@doe.com, and your second group is two"
     */
    
    function format(str, data) {
        var varnames = {};
        function array_path(path, i) {
            var this_k = '[' + i + ']';
            if (!path.length)
                return [this_k];
            path = path.slice();
            path[path.length - 1] += this_k;
            return path;
        }
        function add_varnames(this_data, path) {
            if (this_data.constructor == Array) {
                for (var i = 0; i < this_data.length; i++)
                    add_varnames(this_data[i], array_path(path, i));
            }
            else if (this_data.constructor == Object) {
                for (var k in this_data)
                    add_varnames(this_data[k], path.concat(k));
            }
            else {
                var varname = '{' + path.join('.') + '}';
                varnames[varname] = String(this_data);
            }
        }
        add_varnames(data, []);
        for (var varname in varnames)
            str = str.replace(varname, varnames[varname]);
        return str;
    }
    
    0 讨论(0)
  • 2020-12-13 08:58

    JavaScript doesn't have such a function AFAIK.

    You could create one by modifying the String class's prototype object to add a format() method which takes a variable number of arguments.

    In the format method you'd have to get the String's instance value (the actual string) and then parse it for '{}' and insert the appropriate argument.

    Then return the new string to the caller.

    0 讨论(0)
提交回复
热议问题