JavaScript 等同于 printf / String.Format

我正在寻找一个等效于 C / PHP printf()或 C#/ Java 程序员的String.Format() (适用于. NET 的IFormatProvider String.Format() JavaScript。

我的基本要求是现在使用数字的千位分隔符格式,但是可以处理很多组合(包括日期)的东西会很好。

我意识到 Microsoft 的Ajax库提供了String.Format()的版本,但是我们不希望该框架的全部开销。

答案

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

// 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}

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

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

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


除此以外:

尝试sprintf()for JavaScript


如果您真的想自己做一个简单的格式化方法,请不要先后进行替换,而要同时进行。

因为前面提到的其他替换提议中的大多数其他提议都在先前替换的替换字符串也包含如下格式序列时失败了:

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

通常,您希望输出为{1}{0}但实际输出为{1}{1} 。因此,应同时进行替换,而不是像在噬菌体的建议中那样

这很有趣,因为 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\\}"

整齐。

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 数字格式快速教程

MoFi 的toFixed()参考页 (带有 toPrecision(),toExponential(),toLocaleString()等的链接)

从 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-Template-Strings

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/template_strings

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

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} 将不会被替换。 ;)

我使用以下简单功能:

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")

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

util.format("%s world", "Hello")

我很惊讶没有人使用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'));

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")
);

这是 sprintf 在 JavaScript 中的最小实现:它仅执行 “%s” 和 “%d”,但我留有扩展空间。它对 OP 没有用,但是其他偶然发现来自 Google 的线程的人可能会从中受益。

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

与以往的答复类似的解决方案对比,这其中确实一气呵成所有替换,所以它不会取代先前所取代值的部分。