45 题: JavaScript等效于printf / String.Format

在...创建的问题 Tue, Jul 31, 2018 12:00 AM

我正在寻找一个相当于C /PHP printf()或C#/Java程序员的良好JavaScript,String.Format()(.NET的IFormatProvider)。

我的基本要求是现在有数千个数字分隔符格式,但处理大量组合(包括日期)的东西会很好。

我意识到微软的 Ajax 库提供了String.Format()的版本,但我们不知道不想要那个框架的全部开销。

    
1794
  1. 除了下面的所有优秀答案,你可能想看一下这个: stackoverflow.com/a/2648463/1712065 IMO是解决此问题的最有效方法。
    2015-04-24 02:54:09Z
  2. 我写了一个廉价的使用类似C的printf语法。
    2016-01-28 19:38:26Z
  3. var search = [$scope.dog,“1”]; var url = vsprintf(“ earth /Services /dogSearch.svc /FindMe /%s /%s “,搜索); ***对于节点,您可以通过“npm install sprintf-js”
    获取模块
    2016-04-29 19:25:46Z
  4. 我还写了一个简单的函数来实现这个目的; stackoverflow.com/a/54345052/5927126
    2019-01-24 11:10:19Z
  5. 醇>
    30答案                              30 跨度>                         

    从ES6开始,您可以使用模板字符串:

     
    let soMany = 10;
    console.log(`This is ${soMany} times easier!`);
    // "This is 10 times easier!
    

    有关详细信息,请参阅下面的Kim的答案


    否则:

    尝试使用 sprintf()获取JavaScript


    如果你真的想自己做一个简单的格式化方法,不要连续进行替换,而是同时进行。

    因为当前替换的替换字符串也包含如下格式序列时,提及的大多数其他提议都会失败:

     
    "{0}{1}".format("{1}", "{0}")
    

    通常你会期望输出为{1}{0}但实际输出为{1}{1}。因此,请在 fearphage的建议中同时进行替换。

        
    906
    2019-01-31 19:07:10Z
    1. 2012-06-08 11:36:22Z
    2. 如果只需要一些简单的数字到字符串转换,num.toFixed()方法就足够了!
      2012-12-17 23:29:20Z
    3. @ MaksymilianMajer似乎有些大不相同。
      2014-04-14 21:51:27Z
    4. @ EvanCarroll你是对的。当我写评论时,sprintf() for JavaScript的存储库不可用。除了sprintf之外,underscore.string还有更多功能,它基于sprintf() for JavaScript实现。除此之外,图书馆是一个完全不同的项目。
      2014-04-15 07:41:50Z
    5. 这不应该被接受回答。从ES6开始,它被内置到javascript语言中(在浏览器和NodeJS中)。请参阅下面的@Kim的答案。
      2018-07-02 19:17:41Z
    6. 醇>

    基于之前建议的解决方案:

     
    // First, checks if it isn't implemented yet.
    if (!String.prototype.format) {
      String.prototype.format = function() {
        var args = arguments;
        return this.replace(/{(\d+)}/g, function(match, number) { 
          return typeof args[number] != 'undefined'
            ? args[number]
            : match
          ;
        });
      };
    }
    

    "{0} is dead, but {1} is alive! {0} {2}".format("ASP", "ASP.NET")

    输出

      

    ASP已经死了,但ASP.NET还活着! ASP {2}


    如果你不想修改String的原型:

     
    if (!String.format) {
      String.format = function(format) {
        var args = Array.prototype.slice.call(arguments, 1);
        return format.replace(/{(\d+)}/g, function(match, number) { 
          return typeof args[number] != 'undefined'
            ? args[number] 
            : match
          ;
        });
      };
    }
    

    让您更熟悉:

    String.format('{0} is dead, but {1} is alive! {0} {2}', 'ASP', 'ASP.NET');

    结果相同:

      

    ASP已经死了,但ASP.NET还活着! ASP {2}

        
    1342
    2016-06-29 16:25:30Z
    1. ||如果args [number]为0,则技巧不起作用。应该使用显式if()来查看是否(args [number] === undefined)。
      2011-02-19 14:16:00Z
    2. 在简写的else语句中,为什么不只是“匹配”而不是“'{'+ number +'}'”。 match应该等于该字符串。
      2011-07-10 04:40:13Z
    3. @ ckozl您的代码重新格式化使答案无效。它改变了代码的输出。请在应用修改前测试您的代码。谢谢。
      2014-02-06 14:05:58Z
    4. @ ckozl - 请不要反复覆盖此答案的格式与违者的意愿。我将在第二天将其锁定,如果您想解释为什么要这样做,请在 Meta 上进行解释。
      2014-02-06 15:33:19Z
    5. 除非处理polyfill,否则(!String.prototype.format)检查是一个坏主意,因为这意味着较新的浏览器可能会出现并使用不兼容的format方法破坏您的网站。我建议删除它。
      2014-04-14 13:28:04Z
    6. 醇>

    这很有趣,因为Stack Overflow实际上有String原型的formatUnicorn格式化功能。试试吧!进入控制台并键入以下内容:

     
    "Hello, {name}, are you feeling {adjective}?".formatUnicorn({name:"Gabriel", adjective: "OK"});
    

    你得到这个输出:

    Hello, Gabriel, are you feeling OK?

    您可以使用对象,数组和字符串作为参数!我得到了它的代码并重新编写它以生成新版本的String.prototype.format

     
    String.prototype.formatUnicorn = String.prototype.formatUnicorn ||
    function () {
        "use strict";
        var str = this.toString();
        if (arguments.length) {
            var t = typeof arguments[0];
            var key;
            var args = ("string" === t || "number" === t) ?
                Array.prototype.slice.call(arguments)
                : arguments[0];
    
            for (key in args) {
                str = str.replace(new RegExp("\\{" + key + "\\}", "gi"), args[key]);
            }
        }
    
        return str;
    };
    

    注意聪明的Array.prototype.slice.call(arguments)调用 - 这意味着如果你输入的是字符串或数字的参数,而不是单个JSON样式的对象,你就得到了C#的 String.Format 行为。

     
    "a{0}bcd{1}ef".formatUnicorn("foo", "bar"); // yields "aFOObcdBARef"
    

    那是因为Arrayslice会将arguments中的任何内容强制转换为Array,无论是否原来,key将是每个数组元素强制转换为字符串的索引(0,1,2 ...) (例如,“0”,所以"\\{0\\}"为你的第一个正则表达式模式)。

        
    425
    2017-01-13 15:27:51Z
    1. 使用stackoverflow中的代码回答stackoverflow上的问题非常酷,+ 1
      2014-01-18 00:02:09Z
    2. @ JamesManning正则表达式允许全局标志(g),它可以多次替换相同的键。在上面的示例中,您可以在同一个句子中多次使用{name}并将它们全部替换。
      2014-04-24 13:00:12Z
    3. @ DineiA.Rockenbach,但代码for (arg in args)将定义一个名为arg的全局变量。如果你没有在第一行使用var arg,那么你应该使用for(var arg in args)来避免定义全局变量。
      2015-08-22 14:17:18Z
    4. @ ruffin“有点夸张”?被愚弄为将用户数据解释为格式字符串的代码是整个漏洞类别。 98.44%超越平庸
      2017-06-05 16:17:18Z
    5. @ samhocevar我简直不敢相信你的小鲍比给我做了什么。 ;)如果您在数据库服务器上运行由客户端JavaScript处理的文本而没有任何安全检查,天堂帮助我们所有人。 ; ^)看,不应该有任何任何用户可以从客户端(例如邮递员)发送超过服务器安全性的内容。并且应该假设可能从客户端发送的任何危险。也就是说,如果您需要100%安全来自客户端JavaScript代码 始终用户可编辑,并且您认为此功能可能会带来安全风险,那么您正在玩在错误的游戏中。
      2018-02-19 18:57:04Z
    6. 醇>

    JavaScript中的数字格式

    我到了这个问题页面,希望在不引入另一个库的情况下找到如何在JavaScript中格式化数字。这是我发现的:

    舍入浮点数

    在JavaScript中相当于sprintf("%.2f", num)似乎是num.toFixed(2),它将num格式化为2位小数,并进行四舍五入(但请参阅@ ars265关于Math.round的评论)。

     
    (12.345).toFixed(2); // returns "12.35" (rounding!)
    (12.3).toFixed(2); // returns "12.30" (zero padding)
    

    指数形式

    相当于sprintf("%.2e", num)num.toExponential(2)

     
    (33333).toExponential(2); // "3.33e+4"
    

    十六进制和其他碱基

    要在基本B中打印数字,请尝试num.toString(B)。 JavaScript支持自动转换到基数2到36(此外,某些浏览器有对base64编码的支持有限

     
    (3735928559).toString(16); // to base 16: "deadbeef"
    parseInt("deadbeef", 16); // from base 16: 3735928559
    

    参考页

    有关JS数字格式的快速教程

    toFixed()的Mozilla参考页(含链接到toPrecision(),toExponential(),toLocaleString(),...)

        
    303
    2019-06-27 08:05:11Z
    1. 将数字文字括在括号中不是更好,而不是在那里留下奇怪的空格吗?
      2012-11-26 01:53:24Z
    2. 这可能看起来更好,真实。但我的目标只是指出语法错误陷阱。
      2012-12-01 21:28:06Z
    3. 如果您使用的是较旧的浏览器,或者支持较旧的浏览器,某些浏览器实现错误修复,使用Math.round代替toFixed,则只是旁注溶液
      2013-02-19 14:57:05Z
    4. @ Raphael_和@rescdsk:..也有效:33333..toExponential(2);
      2013-05-07 08:12:01Z
    5. 或(33333).toExponential(2)
      2016-08-19 14:32:50Z
    6. 醇>

    从ES6开始,您可以使用模板字符串

     
    let soMany = 10;
    console.log(`This is ${soMany} times easier!`);
    // "This is 10 times easier!
    

    请注意,模板字符串由反引号包围`而不是(单个)引号。

    更多信息:

    https://developers.google.com/web/updates/2015/01 /ES6 - 模板字符串

    https://developer.mozilla.org/en-US/docs/Web /JavaScript的/参考/template_strings

    注意: 检查mozilla站点以查找支持的浏览器列表。

        
    213
    2016-08-22 17:46:30Z
    1. 模板字符串的问题在于它们似乎立即被执行,使得它们被用作比如类似i18n的字符串表完全没用。我无法在早期定义字符串,并提供稍后和/或重复使用的参数。
      2015-12-04 23:39:13Z
    2. @ Tustin2121你是对的,他们不是为了分配给一个变量而构建的,这有点让人心烦意乱,但它很容易与模板一起工作字符串的即时执行趋势,如果你将它们隐藏在一个函数中。请参见 jsfiddle.net/zvcm70pa
      2016-05-25 03:51:20Z
    3. @ Tustin2121使用模板字符串或旧式字符串连接没有区别,它的糖用于同一件事。你必须在一个简单的函数中包装一个旧样式的字符串生成器,同样的东西适用于字符串模板。 const compile = (x, y) => `I can call this template string whenever I want.. x=${x}, y=${y}` ... compile(30, 20)
      2016-05-27 06:22:36Z
    4. 此解决方案不适用于传递给变量的格式字符串(例如来自服务器)
      2016-11-15 14:06:34Z
    5. @ inanutshellus如果您的模板函数是在执行它的同一台机器上定义的,那么它可以正常工作。据我所知,你不能将函数作为JSON传递,因此在数据库中存储模板函数效果不佳。
      2017-05-04 18:44:54Z
    6. 醇>

    jsxt,Zippo

    此选项更适合。

     
    String.prototype.format = function() {
        var formatted = this;
        for (var i = 0; i < arguments.length; i++) {
            var regexp = new RegExp('\\{'+i+'\\}', 'gi');
            formatted = formatted.replace(regexp, arguments[i]);
        }
        return formatted;
    };
    

    使用此选项,我可以替换这些字符串:

     
    'The {0} is dead. Don\'t code {0}. Code {1} that is open source!'.format('ASP', 'PHP');
    

    使用您的代码,第二个{0}将不会被替换。 ;)

        
    170
    2015-05-07 11:29:46Z
    1. 我喜欢这个,因为它全局替换了格式标记。
      2011-02-05 04:17:16Z
    2. gist.github.com/1049426 我用这种方法更新了你的例子。许多好处,包括保存本机实现(如果存在),字符串化等。我尝试删除正则表达式,但是需要全局替换。 : - /
      2011-06-27 18:46:40Z
    3. 遗憾的是,jsxt是GPL许可的
      2012-07-22 20:24:43Z
    4. 你没有在for循环中声明一个变量
      2013-12-11 19:27:02Z
    5. 醇>

    我使用这个简单的功能:

     
    String.prototype.format = function() {
        var formatted = this;
        for( var arg in arguments ) {
            formatted = formatted.replace("{" + arg + "}", arguments[arg]);
        }
        return formatted;
    };
    

    这与string.format非常相似:

     
    "{0} is dead, but {1} is alive!".format("ASP", "ASP.NET")
    
        
    104
    2014-07-10 23:49:12Z
    1. 为什么+=?,应该formatted = this.replace("{" + arg + "}", arguments[arg]);
      2010-11-30 06:30:18Z
    2. 我认为代码仍然不正确。正确的一个应该像 Filipiz 一样。
      2011-01-11 02:48:33Z
    3. 作为参考,for...in将无法​​在每个浏览器中运行,因为此代码需要它。它将遍历所有可枚举属性,在某些浏览器中将包含arguments.length,而在其他浏览器中甚至根本不包含参数本身。在任何情况下,如果添加Object.prototype,任何添加都可能包含在一堆中。代码应该使用标准的for循环,而不是for...in
      2011-02-06 21:10:09Z
    4. 如果之前的替换包含格式字符串,则会失败:"{0} is dead, but {1} is alive!".format("{1}", "ASP.NET") === "ASP.NET is dead, but ASP.NET is alive!"
      2011-03-28 14:05:04Z
    5. 变量arg是全局变量。你需要这样做:for (var arg in arguments) {
      2012-12-05 22:49:51Z
    6. 醇>

    对于 Node.js 用户, util.format ,具有类似printf的功能:

     
    util.format("%s world", "Hello")
    
        
    60
    2017-10-09 02:10:12Z
    1. 从node v0.10.26开始,这不支持%x
      2014-04-24 13:16:43Z
    2. 不支持宽度和对齐修改器(例如%-20s %5.2f
      2019-01-04 13:29:05Z
    3. 醇>

    以下是JavaScript中sprintf的 minimal 实现:它只执行“%s”和“%d”,但我留出了空间来扩展它。它对OP来说毫无用处,但其他偶然发现来自谷歌的人可能会从中受益。

     
    function sprintf() {
        var args = arguments,
        string = args[0],
        i = 1;
        return string.replace(/%((%)|s|d)/g, function (m) {
            // m is the matched format, e.g. %s, %d
            var val = null;
            if (m[2]) {
                val = m[2];
            } else {
                val = args[i];
                // A switch statement so that the formatter can be extended. Default is %s
                switch (m) {
                    case '%d':
                        val = parseFloat(val);
                        if (isNaN(val)) {
                            val = 0;
                        }
                        break;
                }
                i++;
            }
            return val;
        });
    }
    

    示例:

     
    alert(sprintf('Latitude: %s, Longitude: %s, Count: %d', 41.847, -87.661, 'two'));
    // Expected output: Latitude: 41.847, Longitude: -87.661, Count: 0
    

    与之前回复中的类似解决方案相比,这个解决方案一次性完成所有替换 ,因此它不会替换以前替换的部分值。

        
    49
    2015-03-06 21:18:17Z

    我很惊讶没有人使用过 reduce ,这是一个原生简洁而强大的JavaScript函数。

    ES6(EcmaScript2015)

     
    String.prototype.format = function() {
      return [...arguments].reduce((p,c) => p.replace(/%s/,c), this);
    };
    
    console.log('Is that a %s or a %s?... No, it\'s %s!'.format('plane', 'bird', 'SOman'));

    &LT; ES6

     
    function interpolate(theString, argumentArray) {
        var regex = /%s/;
        var _r=function(p,c){return p.replace(regex,c);}
        return argumentArray.reduce(_r, theString);
    }
    
    interpolate("%s, %s and %s", ["Me", "myself", "I"]); // "Me, myself and I"
    

    工作原理:

      

    reduce 对累加器和数组中的每个元素(从左到右)应用一个函数,将其减少为单个值。

     
    var _r= function(p,c){return p.replace(/%s/,c)};
    
    console.log(
      ["a", "b", "c"].reduce(_r, "[%s], [%s] and [%s]") + '\n',
      [1, 2, 3].reduce(_r, "%s+%s=%s") + '\n',
      ["cool", 1337, "stuff"].reduce(_r, "%s %s %s")
    );
        
    48
    2018-02-21 14:50:51Z
    1. 这是一个使用这种方法创建简化的printf函数的版本: jsfiddle.net/11szrbx9
      2015-07-20 22:49:10Z
    2. 这是另一个使用ES6,在一行:(...a) => {return a.reduce((p: string, c: any) => p.replace(/%s/, c));
      2018-02-22 11:59:52Z
    3. 在ES6中不需要String.prototype.format((a,b,c)=>`${a}, ${b} and ${c}`)(...['me', 'myself', 'I'])(请注意,这有点多余,以便更好地适合您的示例)
      2018-04-05 21:50:52Z
    4. 您必须为printf的每个类型说明符实现替换函数,并包含填充前缀的逻辑。 imho,以明智的方式迭代格式字符串似乎是一个小小的挑战。如果您只需要字符串替换,那么整洁的解决方案。
      2018-07-06 10:19:35Z
    5. 醇>

    JavaScript程序员可以在 https上使用String.prototype.sprintf: //github.com/ildar-shaimordanov/jsxt/blob/master/js/String.js 。以下是示例:

     
    var d = new Date();
    var dateStr = '%02d:%02d:%02d'.sprintf(
        d.getHours(), 
        d.getMinutes(), 
        d.getSeconds());
    
        
    31
    2016-11-20 10:51:39Z
    1. code.google.com是一个死链接
      2016-11-16 09:38:51Z
    2. @JasonMorgan,我已经在GitHub上分享了工作链接。查看更正后的答案。
      2016-11-20 10:52:16Z
    3. 醇>

    +1 Zippo,但函数体必须如下所示,否则它会在每次迭代时附加当前字符串:

     
    String.prototype.format = function() {
        var formatted = this;
        for (var arg in arguments) {
            formatted = formatted.replace("{" + arg + "}", arguments[arg]);
        }
        return formatted;
    };
    
        
    21
    2014-07-10 23:50:07Z
    1. 它在Firefox上不起作用。调试器显示arg为undefined。
      2010-12-11 10:27:01Z
    2. 是的我没有正确发布代码,谢谢你修复:)
      2010-12-11 13:08:00Z
    3. 它不会替换第二个字符'The {0} is dead. Don\'t code {0}. Code {1} that is open source!'.format('ASP', 'PHP'); ,结果变为The ASP is dead. Don't code {0}. Code PHP that is open source!。还有一件事for(arg in arguments)在IE中不起作用。我换成了for (arg = 0; arg <arguments.length; arg++)
      2011-01-28 01:52:08Z
    4. 作为参考,for...in将无法​​在每个浏览器中运行,因为此代码需要它。它将遍历所有可枚举属性,在某些浏览器中将包含arguments.length,而在其他浏览器中甚至根本不包含参数本身。在任何情况下,如果添加Object.prototype,任何添加都可能包含在一堆中。代码应该使用标准的for循环,而不是for...in
      2011-02-06 21:12:13Z
    5. 您应该提出答案编辑而不是重复答案。这个重复的此答案
      2019-05-09 09:16:32Z
    6. 醇>

    添加到zippoxer的答案,我使用此功能:

     
    String.prototype.format = function () {
        var a = this, b;
        for (b in arguments) {
            a = a.replace(/%[a-z]/, arguments[b]);
        }
        return a; // Make chainable
    };
    
    var s = 'Hello %s The magic number is %d.';
    s.format('world!', 12); // Hello World! The magic number is 12.
    

    我还有一个非原型版本,我经常使用它的Java语法:

     
    function format() {
        var a, b, c;
        a = arguments[0];
        b = [];
        for(c = 1; c < arguments.length; c++){
            b.push(arguments[c]);
        }
        for (c in b) {
            a = a.replace(/%[a-z]/, b[c]);
        }
        return a;
    }
    format('%d ducks, 55 %s', 12, 'cats'); // 12 ducks, 55 cats
    

    ES 2015更新

    ES 2015中所有酷炫的新东西都让这更容易:

     
    function format(fmt, ...args){
        return fmt
            .split("%%")
            .reduce((aggregate, chunk, i) =>
                aggregate + chunk + (args[i] || ""), "");
    }
    
    format("Hello %%! I ate %% apples today.", "World", 44);
    // "Hello World, I ate 44 apples today."
    

    我认为,由于这与旧版本一样,实际上并不解析字母,所以也可以使用单个标记%%。这有利它是显而易见的,并没有使用单个%变得困难。但是,如果由于某种原因需要%%,则需要将其替换为自身:

     
    format("I love percentage signs! %%", "%%");
    // "I love percentage signs! %%"
    
        
    20
    2018-08-01 20:59:12Z
    1. 这个答案非常适合快速复制粘贴到现有函数中。不要求没有下载等。
      2017-06-24 20:41:52Z
    2. @ Nick yep,这就是主意:)
      2017-06-25 03:08:18Z
    3. 醇>

    我会添加自己的发现,因为我问过:

    可悲的是,似乎sprintf没有像.NET的字符串格式那样处理千位分隔符格式。

        
    15
    2017-03-27 19:12:44Z

    我使用了一个名为 String.format for JavaScript 的小型库,它支持大部分格式字符串功能(包括数字和日期的格式),并使用.NET语法。脚本本身小于4 kB,因此不会产生太多开销。

        
    14
    2009-09-27 08:36:00Z
    1. 我看了看那个库,看起来真的很棒。当我看到下载是EXE时,我很生气。那是什么意思?没下载。
      2010-04-06 18:04:51Z
    2. 不再是exe,看起来非常棒。
      2010-06-17 19:01:57Z
    3. 一个EXE的可下载档案通常只不过是一个“自解压ZIP”。执行它,它将自行解压缩。这非常方便,但因为它看起来非常像恶意软件,所以通常不再在网络上使用该格式。
      2013-07-01 07:46:47Z
    4. 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供参考链接。如果链接页面发生更改,仅链接答案可能会无效。
      2014-06-24 04:56:33Z
    5. @ starmole链接是一个(缩小的)4 kB javascript 。我不相信将其粘贴到答案中是一个好主意。
      2014-06-24 05:07:58Z
    6. 醇>

    非常优雅:

     
    String.prototype.format = function (){
        var args = arguments;
        return this.replace(/\{\{|\}\}|\{(\d+)\}/g, function (curlyBrack, index) {
            return ((curlyBrack == "{{") ? "{" : ((curlyBrack == "}}") ? "}" : args[index]));
        });
    };
    
    // Usage:
    "{0}{1}".format("{1}", "{0}")
    

    归功于 (链接断开) https://gist.github.com/0i0/1519811     

    14
    2015-01-02 10:29:06Z
    1. 这是唯一一个处理转义括号{{0}}以及像{0}{1}.format("{1}", "{0}")这样的东西。应该在最顶端!
      2014-07-09 06:54:11Z
    2. 醇>

    我想分享我对“问题”的解决方案。我没有重新发明轮子,但试图找到一个基于JavaScript已经做的解决方案。优点是,您可以免费获得所有隐式转换。设置String的prototype属性$提供了非常好的紧凑语法(参见下面的示例)。它可能不是最有效的方式,但在大多数情况下处理输出它不必进行超级优化。

     
    String.form = function(str, arr) {
        var i = -1;
        function callback(exp, p0, p1, p2, p3, p4) {
            if (exp=='%%') return '%';
            if (arr[++i]===undefined) return undefined;
            exp  = p2 ? parseInt(p2.substr(1)) : undefined;
            var base = p3 ? parseInt(p3.substr(1)) : undefined;
            var val;
            switch (p4) {
                case 's': val = arr[i]; break;
                case 'c': val = arr[i][0]; break;
                case 'f': val = parseFloat(arr[i]).toFixed(exp); break;
                case 'p': val = parseFloat(arr[i]).toPrecision(exp); break;
                case 'e': val = parseFloat(arr[i]).toExponential(exp); break;
                case 'x': val = parseInt(arr[i]).toString(base?base:16); break;
                case 'd': val = parseFloat(parseInt(arr[i], base?base:10).toPrecision(exp)).toFixed(0); break;
            }
            val = typeof(val)=='object' ? JSON.stringify(val) : val.toString(base);
            var sz = parseInt(p1); /* padding size */
            var ch = p1 && p1[0]=='0' ? '0' : ' '; /* isnull? */
            while (val.length<sz) val = p0 !== undefined ? val+ch : ch+val; /* isminus? */
           return val;
        }
        var regex = /%(-)?(0?[0-9]+)?([.][0-9]+)?([#][0-9]+)?([scfpexd%])/g;
        return str.replace(regex, callback);
    }
    
    String.prototype.$ = function() {
        return String.form(this, Array.prototype.slice.call(arguments));
    }
    

    以下是一些例子:

     
    String.format("%s %s", [ "This is a string", 11 ])
    console.log("%s %s".$("This is a string", 11))
    var arr = [ "12.3", 13.6 ]; console.log("Array: %s".$(arr));
    var obj = { test:"test", id:12 }; console.log("Object: %s".$(obj));
    console.log("%c", "Test");
    console.log("%5d".$(12)); // '   12'
    console.log("%05d".$(12)); // '00012'
    console.log("%-5d".$(12)); // '12   '
    console.log("%5.2d".$(123)); // '  120'
    console.log("%5.2f".$(1.1)); // ' 1.10'
    console.log("%10.2e".$(1.1)); // '   1.10e+0'
    console.log("%5.3p".$(1.12345)); // ' 1.12'
    console.log("%5x".$(45054)); // ' affe'
    console.log("%20#2x".$("45054")); // '    1010111111111110'
    console.log("%6#2d".$("111")); // '     7'
    console.log("%6#16d".$("affe")); // ' 45054'
    
        
    14
    2018-05-29 12:55:32Z
    1. 遗憾的是,至少#和+没有为浮点数实现。以下是c中函数的参考: tutorialspoint.com/c_standard_library/c_function_sprintf.htm
      2018-05-29 13:40:02Z
    2. 醇>

    如果您要处理千位分隔符,您应该使用JavaScript中的toLocaleString() Number 类,因为它将格式化用户区域的字符串。

    JavaScript 日期类可以设置本地化日期和时间的格式。

        
    11
    2014-07-10 23:48:13Z
    1. 它实际上是由用户设置为应用程序中的设置(不是他们的机器)但是我会看看,谢谢
      2009-03-04 13:19:19Z
    2. 添加一些示例,以便每个人都能快速理解它。
      2014-06-24 04:57:09Z
    3. 醇>

    我有一个非常接近彼得的解决方案,但它涉及数字和对象案例。

     
    if (!String.prototype.format) {
      String.prototype.format = function() {
        var args;
        args = arguments;
        if (args.length === 1 && args[0] !== null && typeof args[0] === 'object') {
          args = args[0];
        }
        return this.replace(/{([^}]*)}/g, function(match, key) {
          return (typeof args[key] !== "undefined" ? args[key] : match);
        });
      };
    }
    

    也许处理所有深层次案件可能更好,但是对于我的需求,这很好。

     
    "This is an example from {name}".format({name:"Blaine"});
    "This is an example from {0}".format("Blaine");
    

    PS:如果您在 AngularJS 等模板框架中使用翻译,这个功能非常酷:

     
    <h1> {{('hello-message'|translate).format(user)}} <h1>
    <h1> {{('hello-by-name'|translate).format( user ? user.name : 'You' )}} <h1>
    

    en.json就像

     
    {
        "hello-message": "Hello {name}, welcome.",
        "hello-by-name": "Hello {0}, welcome."
    }
    
        
    9
    2014-09-30 17:55:27Z
    1. regexp中的[^}]部分是不必要的..使用{(。*?)}代替,或者更好{([\s \S] *? )}也匹配换行符。
      2014-10-01 08:26:18Z
    2. 醇>

    PHPJS项目已经为许多PHP函数编写了JavaScript实现。由于PHP的sprintf()功能与C的printf()基本相同,因此它们的JavaScript实现应满足您的需求。     

    8
    2014-07-10 23:52:19Z

    我用这个:

     
    String.prototype.format = function() {
        var newStr = this, i = 0;
        while (/%s/.test(newStr))
            newStr = newStr.replace("%s", arguments[i++])
    
        return newStr;
    }
    

    然后我称之为:

     
    "<h1>%s</h1><p>%s</p>".format("Header", "Just a test!");
    
        
    8
    2014-08-14 07:01:49Z
    1. 这不适用于'my string%s hello%s'.format('%s')...
      2014-10-01 08:28:24Z
    2. 醇>

    一个非常不同的版本,我更喜欢的版本(这个版本使用{xxx}令牌而不是{0}编号参数,这更加自我记录并且更适合本地化:

     
    String.prototype.format = function(tokens) {
      var formatted = this;
      for (var token in tokens)
        if (tokens.hasOwnProperty(token))
          formatted = formatted.replace(RegExp("{" + token + "}", "g"), tokens[token]);
      return formatted;
    };
    

    变化将是:

     
      var formatted = l(this);
    

    首先调用l()本地化函数。

        
    7
    2012-10-11 15:40:03Z

    对于那些喜欢 Node.JS 及其 util.format 功能,我刚将其解压缩为其vanilla JavaScript表单(仅包含util.format使用的函数):

     
    exports = {};
    
    function isString(arg) {
        return typeof arg === 'string';
    }
    function isNull(arg) {
        return arg === null;
    }
    function isObject(arg) {
        return typeof arg === 'object' && arg !== null;
    }
    function isBoolean(arg) {
        return typeof arg === 'boolean';
    }
    function isUndefined(arg) {
        return arg === void 0;
    }
    function stylizeNoColor(str, styleType) {
        return str;
    }
    function stylizeWithColor(str, styleType) {
        var style = inspect.styles[styleType];
    
        if (style) {
            return '\u001b[' + inspect.colors[style][0] + 'm' + str +
                '\u001b[' + inspect.colors[style][3] + 'm';
        } else {
            return str;
        }
    }
    function isFunction(arg) {
        return typeof arg === 'function';
    }
    function isNumber(arg) {
        return typeof arg === 'number';
    }
    function isSymbol(arg) {
        return typeof arg === 'symbol';
    }
    function formatPrimitive(ctx, value) {
        if (isUndefined(value))
            return ctx.stylize('undefined', 'undefined');
        if (isString(value)) {
            var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
                    .replace(/'/g, "\\'")
                    .replace(/\\"/g, '"') + '\'';
            return ctx.stylize(simple, 'string');
        }
        if (isNumber(value)) {
            // Format -0 as '-0'. Strict equality won't distinguish 0 from -0,
            // so instead we use the fact that 1 / -0 < 0 whereas 1 / 0 > 0 .
            if (value === 0 && 1 / value < 0)
                return ctx.stylize('-0', 'number');
            return ctx.stylize('' + value, 'number');
        }
        if (isBoolean(value))
            return ctx.stylize('' + value, 'boolean');
        // For some reason typeof null is "object", so special case here.
        if (isNull(value))
            return ctx.stylize('null', 'null');
        // es6 symbol primitive
        if (isSymbol(value))
            return ctx.stylize(value.toString(), 'symbol');
    }
    function arrayToHash(array) {
        var hash = {};
    
        array.forEach(function (val, idx) {
            hash[val] = true;
        });
    
        return hash;
    }
    function objectToString(o) {
        return Object.prototype.toString.call(o);
    }
    function isDate(d) {
        return isObject(d) && objectToString(d) === '[object Date]';
    }
    function isError(e) {
        return isObject(e) &&
            (objectToString(e) === '[object Error]' || e instanceof Error);
    }
    function isRegExp(re) {
        return isObject(re) && objectToString(re) === '[object RegExp]';
    }
    function formatError(value) {
        return '[' + Error.prototype.toString.call(value) + ']';
    }
    function formatPrimitiveNoColor(ctx, value) {
        var stylize = ctx.stylize;
        ctx.stylize = stylizeNoColor;
        var str = formatPrimitive(ctx, value);
        ctx.stylize = stylize;
        return str;
    }
    function isArray(ar) {
        return Array.isArray(ar);
    }
    function hasOwnProperty(obj, prop) {
        return Object.prototype.hasOwnProperty.call(obj, prop);
    }
    function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
        var name, str, desc;
        desc = Object.getOwnPropertyDescriptor(value, key) || {value: value[key]};
        if (desc.get) {
            if (desc.set) {
                str = ctx.stylize('[Getter/Setter]', 'special');
            } else {
                str = ctx.stylize('[Getter]', 'special');
            }
        } else {
            if (desc.set) {
                str = ctx.stylize('[Setter]', 'special');
            }
        }
        if (!hasOwnProperty(visibleKeys, key)) {
            name = '[' + key + ']';
        }
        if (!str) {
            if (ctx.seen.indexOf(desc.value) < 0) {
                if (isNull(recurseTimes)) {
                    str = formatValue(ctx, desc.value, null);
                } else {
                    str = formatValue(ctx, desc.value, recurseTimes - 1);
                }
                if (str.indexOf('\n') > -1) {
                    if (array) {
                        str = str.split('\n').map(function (line) {
                            return '  ' + line;
                        }).join('\n').substr(2);
                    } else {
                        str = '\n' + str.split('\n').map(function (line) {
                            return '   ' + line;
                        }).join('\n');
                    }
                }
            } else {
                str = ctx.stylize('[Circular]', 'special');
            }
        }
        if (isUndefined(name)) {
            if (array && key.match(/^\d+$/)) {
                return str;
            }
            name = JSON.stringify('' + key);
            if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
                name = name.substr(1, name.length - 2);
                name = ctx.stylize(name, 'name');
            } else {
                name = name.replace(/'/g, "\\'")
                    .replace(/\\"/g, '"')
                    .replace(/(^"|"$)/g, "'")
                    .replace(/\\\\/g, '\\');
                name = ctx.stylize(name, 'string');
            }
        }
    
        return name + ': ' + str;
    }
    function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {
        var output = [];
        for (var i = 0, l = value.length; i < l; ++i) {
            if (hasOwnProperty(value, String(i))) {
                output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
                    String(i), true));
            } else {
                output.push('');
            }
        }
        keys.forEach(function (key) {
            if (!key.match(/^\d+$/)) {
                output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
                    key, true));
            }
        });
        return output;
    }
    function reduceToSingleString(output, base, braces) {
        var length = output.reduce(function (prev, cur) {
            return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1;
        }, 0);
    
        if (length > 60) {
            return braces[0] +
                (base === '' ? '' : base + '\n ') +
                ' ' +
                output.join(',\n  ') +
                ' ' +
                braces[1];
        }
    
        return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
    }
    function formatValue(ctx, value, recurseTimes) {
        // Provide a hook for user-specified inspect functions.
        // Check that value is an object with an inspect function on it
        if (ctx.customInspect &&
            value &&
            isFunction(value.inspect) &&
                // Filter out the util module, it's inspect function is special
            value.inspect !== exports.inspect &&
                // Also filter out any prototype objects using the circular check.
            !(value.constructor && value.constructor.prototype === value)) {
            var ret = value.inspect(recurseTimes, ctx);
            if (!isString(ret)) {
                ret = formatValue(ctx, ret, recurseTimes);
            }
            return ret;
        }
    
        // Primitive types cannot have properties
        var primitive = formatPrimitive(ctx, value);
        if (primitive) {
            return primitive;
        }
    
        // Look up the keys of the object.
        var keys = Object.keys(value);
        var visibleKeys = arrayToHash(keys);
    
        if (ctx.showHidden) {
            keys = Object.getOwnPropertyNames(value);
        }
    
        // This could be a boxed primitive (new String(), etc.), check valueOf()
        // NOTE: Avoid calling `valueOf` on `Date` instance because it will return
        // a number which, when object has some additional user-stored `keys`,
        // will be printed out.
        var formatted;
        var raw = value;
        try {
            // the .valueOf() call can fail for a multitude of reasons
            if (!isDate(value))
                raw = value.valueOf();
        } catch (e) {
            // ignore...
        }
    
        if (isString(raw)) {
            // for boxed Strings, we have to remove the 0-n indexed entries,
            // since they just noisey up the output and are redundant
            keys = keys.filter(function (key) {
                return !(key >= 0 && key < raw.length);
            });
        }
    
        // Some type of object without properties can be shortcutted.
        if (keys.length === 0) {
            if (isFunction(value)) {
                var name = value.name ? ': ' + value.name : '';
                return ctx.stylize('[Function' + name + ']', 'special');
            }
            if (isRegExp(value)) {
                return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
            }
            if (isDate(value)) {
                return ctx.stylize(Date.prototype.toString.call(value), 'date');
            }
            if (isError(value)) {
                return formatError(value);
            }
            // now check the `raw` value to handle boxed primitives
            if (isString(raw)) {
                formatted = formatPrimitiveNoColor(ctx, raw);
                return ctx.stylize('[String: ' + formatted + ']', 'string');
            }
            if (isNumber(raw)) {
                formatted = formatPrimitiveNoColor(ctx, raw);
                return ctx.stylize('[Number: ' + formatted + ']', 'number');
            }
            if (isBoolean(raw)) {
                formatted = formatPrimitiveNoColor(ctx, raw);
                return ctx.stylize('[Boolean: ' + formatted + ']', 'boolean');
            }
        }
    
        var base = '', array = false, braces = ['{', '}'];
    
        // Make Array say that they are Array
        if (isArray(value)) {
            array = true;
            braces = ['[', ']'];
        }
    
        // Make functions say that they are functions
        if (isFunction(value)) {
            var n = value.name ? ': ' + value.name : '';
            base = ' [Function' + n + ']';
        }
    
        // Make RegExps say that they are RegExps
        if (isRegExp(value)) {
            base = ' ' + RegExp.prototype.toString.call(value);
        }
    
        // Make dates with properties first say the date
        if (isDate(value)) {
            base = ' ' + Date.prototype.toUTCString.call(value);
        }
    
        // Make error with message first say the error
        if (isError(value)) {
            base = ' ' + formatError(value);
        }
    
        // Make boxed primitive Strings look like such
        if (isString(raw)) {
            formatted = formatPrimitiveNoColor(ctx, raw);
            base = ' ' + '[String: ' + formatted + ']';
        }
    
        // Make boxed primitive Numbers look like such
        if (isNumber(raw)) {
            formatted = formatPrimitiveNoColor(ctx, raw);
            base = ' ' + '[Number: ' + formatted + ']';
        }
    
        // Make boxed primitive Booleans look like such
        if (isBoolean(raw)) {
            formatted = formatPrimitiveNoColor(ctx, raw);
            base = ' ' + '[Boolean: ' + formatted + ']';
        }
    
        if (keys.length === 0 && (!array || value.length === 0)) {
            return braces[0] + base + braces[1];
        }
    
        if (recurseTimes < 0) {
            if (isRegExp(value)) {
                return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
            } else {
                return ctx.stylize('[Object]', 'special');
            }
        }
    
        ctx.seen.push(value);
    
        var output;
        if (array) {
            output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);
        } else {
            output = keys.map(function (key) {
                return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);
            });
        }
    
        ctx.seen.pop();
    
        return reduceToSingleString(output, base, braces);
    }
    function inspect(obj, opts) {
        // default options
        var ctx = {
            seen: [],
            stylize: stylizeNoColor
        };
        // legacy...
        if (arguments.length >= 3) ctx.depth = arguments[2];
        if (arguments.length >= 4) ctx.colors = arguments[3];
        if (isBoolean(opts)) {
            // legacy...
            ctx.showHidden = opts;
        } else if (opts) {
            // got an "options" object
            exports._extend(ctx, opts);
        }
        // set default options
        if (isUndefined(ctx.showHidden)) ctx.showHidden = false;
        if (isUndefined(ctx.depth)) ctx.depth = 2;
        if (isUndefined(ctx.colors)) ctx.colors = false;
        if (isUndefined(ctx.customInspect)) ctx.customInspect = true;
        if (ctx.colors) ctx.stylize = stylizeWithColor;
        return formatValue(ctx, obj, ctx.depth);
    }
    exports.inspect = inspect;
    
    
    // http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
    inspect.colors = {
        'bold': [1, 22],
        'italic': [3, 23],
        'underline': [4, 24],
        'inverse': [7, 27],
        'white': [37, 39],
        'grey': [90, 39],
        'black': [30, 39],
        'blue': [34, 39],
        'cyan': [36, 39],
        'green': [32, 39],
        'magenta': [35, 39],
        'red': [31, 39],
        'yellow': [33, 39]
    };
    
    // Don't use 'blue' not visible on cmd.exe
    inspect.styles = {
        'special': 'cyan',
        'number': 'yellow',
        'boolean': 'yellow',
        'undefined': 'grey',
        'null': 'bold',
        'string': 'green',
        'symbol': 'green',
        'date': 'magenta',
        // "name": intentionally not styling
        'regexp': 'red'
    };
    
    
    var formatRegExp = /%[sdj%]/g;
    exports.format = function (f) {
        if (!isString(f)) {
            var objects = [];
            for (var j = 0; j < arguments.length; j++) {
                objects.push(inspect(arguments[j]));
            }
            return objects.join(' ');
        }
    
        var i = 1;
        var args = arguments;
        var len = args.length;
        var str = String(f).replace(formatRegExp, function (x) {
            if (x === '%%') return '%';
            if (i >= len) return x;
            switch (x) {
                case '%s':
                    return String(args[i++]);
                case '%d':
                    return Number(args[i++]);
                case '%j':
                    try {
                        return JSON.stringify(args[i++]);
                    } catch (_) {
                        return '[Circular]';
                    }
                default:
                    return x;
            }
        });
        for (var x = args[i]; i < len; x = args[++i]) {
            if (isNull(x) || !isObject(x)) {
                str += ' ' + x;
            } else {
                str += ' ' + inspect(x);
            }
        }
        return str;
    };
    

    来自: https://github.com/joyent/node/blob/master/LIB /util.js中

        
    6
    2015-01-23 04:47:21Z

    我有一个稍长的JavaScript格式化程序这里 ......

    您可以通过多种方式进行格式化:

    • String.format(input, args0, arg1, ...)
    • String.format(input, obj)
    • "literal".format(arg0, arg1, ...)
    • "literal".format(obj)

    另外,如果您说ObjectBase.prototype.format(例如使用 DateJS ),它将使用这一点。

    ...实例

     
    var input = "numbered args ({0}-{1}-{2}-{3})";
    console.log(String.format(input, "first", 2, new Date()));
    //Outputs "numbered args (first-2-Thu May 31 2012...Time)-{3})"
    
    console.log(input.format("first", 2, new Date()));
    //Outputs "numbered args(first-2-Thu May 31 2012...Time)-{3})"
    
    console.log(input.format(
        "object properties ({first}-{second}-{third:yyyy-MM-dd}-{fourth})"
        ,{
            'first':'first'
            ,'second':2
            ,'third':new Date() //assumes Date.prototype.format method
        }
    ));
    //Outputs "object properties (first-2-2012-05-31-{3})"
    

    我也使用.asFormat别名并且已经有一些检测,以防已经有一个string.format(例如使用MS Ajax Toolkit(我讨厌那个库)。

        
    5
    2014-07-10 23:56:28Z

    以防万一有人需要一个功能来防止污染全局范围,以下是执行相同操作的功能:

     
      function _format (str, arr) {
        return str.replace(/{(\d+)}/g, function (match, number) {
          return typeof arr[number] != 'undefined' ? arr[number] : match;
        });
      };
    
        
    5
    2015-01-20 09:15:57Z

    基本格式:

     
    var template = jQuery.validator.format("{0} is not a valid value");
    var result = template("abc");
    
        
    5
    2015-12-08 14:18:22Z

    我没有看到String.format变体:

     
    String.format = function (string) {
        var args = Array.prototype.slice.call(arguments, 1, arguments.length);
        return string.replace(/{(\d+)}/g, function (match, number) {
            return typeof args[number] != "undefined" ? args[number] : match;
        });
    };
    
        
    2
    2012-10-10 07:53:36Z

    用于jQuery.ajax()成功函数。只传递一个参数,并将字符串替换为该对象的属性{propertyName}:

     
    String.prototype.format = function () {
        var formatted = this;
        for (var prop in arguments[0]) {
            var regexp = new RegExp('\\{' + prop + '\\}', 'gi');
            formatted = formatted.replace(regexp, arguments[0][prop]);
        }
        return formatted;
    };
    

    示例:

     
    var userInfo = ("Email: {Email} - Phone: {Phone}").format({ Email: "someone@somewhere.com", Phone: "123-123-1234" });
    
        
    2
    2013-02-01 05:40:12Z

    使用sprintf.js - 可以制作一个漂亮的小格式 -

     
    String.prototype.format = function(){
        var _args = arguments 
        Array.prototype.unshift.apply(_args,[this])
        return sprintf.apply(undefined,_args)
    }   
    // this gives you:
    "{%1$s}{%2$s}".format("1", "0")
    // {1}{0}
    
        
    2
    2013-03-04 19:26:59Z
来源放置 这里
其他问题