JavaScript对应于printf/String.Format的函数

2411

我正在寻找一个良好的JavaScript等价物来替代C/PHP中的printf()或对于C#/Java程序员,String.Format()(.NET使用 IFormatProvider)。

我的基本要求是数字的千位分隔符格式,但能处理许多组合(包括日期)的东西会更好。

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


4
除了下面众多优秀的回答,您或许也想看看这个链接:https://dev59.com/pXNA5IYBdhLWcg3wPbSe#2648463,在我看来,这是解决此问题最高效的方法。 - Annie
3
我写了一个简单的程序,使用类C语言的printf语法。 - Braden Best
var search = [$scope.dog, "1"]; var url = vsprintf("http://earth/Services/dogSearch.svc/FindMe/%s/%s", search); ***对于Node,您可以通过“npm install sprintf-js”获取您的模块。 - Jenna Leaf
5
这里的大多数答案都令人失望。printf和String.Format不仅仅是简单的模板,而且问题特别提到了千位分隔符,这是简单模板解决方案都无法处理的。 - blm
除了“模板字符串”之外,人们可能还在寻找String.padStart。 (请参见https://dev59.com/jXE85IYBdhLWcg3wnU-p) - Nor.Z
显示剩余3条评论
61个回答

1

String.prototype.format = function(){
    var final = String(this);
    for(let i=0; i<arguments.length;i++){
        final = final.replace(`%s${i+1}`, arguments[i])
    }
    return final || ''
}

console.log(("hello %s2 how %s3 you %s1").format('hi', 'hello', 'how'));
<h1 id="text">
   
</h1>


1

我使用模板字面量的方法,如下所示:

export const messages = {
  foo: (arg1, arg2) => `Hello ${arg1} ${arg2}`,
  bar: (arg1) => `Hello ${arg1}`,
}

来自文件:

console.log(messages.foo('Bar', 'World'))
console.log(messages.bar('Foo'))

0
你可以使用这个函数。
            String.prototype.format = function (args) {
            var str = this;
            return str.replace(String.prototype.format.regex, function(item) {
                var intVal = parseInt(item.substring(1, item.length - 1));
                var replace;
                if (intVal >= 0) {
                    replace = args[intVal];
                } else if (intVal === -1) {
                    replace = "{";
                } else if (intVal === -2) {
                    replace = "}";
                } else {
                    replace = "";
                }
                return replace;
            });
        };
        String.prototype.format.regex = new RegExp("{-?[0-9]+}", "g");

        // Sample usage.
        var str = "She {1} {0}{2} by the {0}{3}. {-1}^_^{-2}";
        str = str.format(["sea", "sells", "shells", "shore"]);
        alert(str);

使用 parseInt(),就像 @hienbt88 在这里使用的一样,在性能方面会产生令人惊讶的竞争力... 我在这里对这个想法进行了整理,并尝试了一个缓存正则表达式的变体:http://jsperf.com/stringformat/6#results - parseInt() 的实现位于或接近顶部(与从此问题的答案中发布的片段中收集的其他 String.format() 版本相比)。 - fish2000

0

修改了旧答案的代码https://dev59.com/YXRB5IYBdhLWcg3weXOX#18234317,更加高效(没有慢速RegExp)和更短

String.prototype.formatUnicorn = function () {
    let str = this.toString();
    if(!arguments.length) {
        return;
    };
    const [args] = arguments;
    for (const key of Object.keys(args)) {
        str = str.replaceAll(`{${key}}`, args[key]);
    };
    return str;
};

用法:

"{test} {test_2} {test}".formatUnicorn({"test": "hello", "test_2": "world"}); // yields hello world hello

新旧版本的基准测试:https://jsben.ch/BRovx


0

我需要更进一步的解决方案。

一个模板,我可以重复使用它来生成字符串,不仅在声明时,还可以在执行时间的任意时刻生成。

所以我找到了这个工具:

 class Texplate{
    constructor(...args){
        this.data = args;
    }

    apply(...args){
        var text = "";
        var i = 0, j = 0, n = this.data.length, m = args.length;
        for(;i < n && j < m; i++, j++){
            text += this.data[i] + args[j];
        }

        for (; i < n; i++){
            text += this.data[i];
        }

        for (; j < m; j++){
            text += args[j];
        }

        return text;        
    }
}

这允许创建一个文本模板,它在内部作为数组合并算法工作,从构造函数中定义的文本数组开始。

使用示例:

var Textplate example = new Texplate("Hello, ", "!"); 
console.log(example.apply("Frank"));
console.log(example.apply("Mary"));
console.log(example.apply());
console.log(example.apply("Frank", " Have a good day!"));

0

好的,首先我们将设置一些变量来使用:

    const date = new Date();
    
    const locale = 'en-us';
    
    const wDay   = date.toLocaleString(locale, {weekday: 'short'});
    const month  = date.toLocaleString(locale, {month: 'long'});
    const year   = date.toLocaleString(locale, {year: 'numeric'});
    const minute = date.toLocaleString(locale, {minute: 'numeric'});
    const [hour, ap] = date.toLocaleString(locale, {hour: 'numeric', hour12:true}).split(' ');
    
    let mDay = date.toLocaleString(locale, {day: 'numeric'});
    
    switch(mDay % 10)
    {
        case 1:  mDay += 'st'; break;
        case 2:  mDay += 'nd'; break;
        case 3:  mDay += 'rd'; break;
        default: mDay += 'th'; break;
    }

现在我们已经掌握了所有这些,我们可以像这样格式化一个字符串:

    const formatter = (...a) => `${a[0]}, the ${a[1]} of ${a[2]} ${a[3]} at ${a[4]}:${a[5]} ${a[6]}`;
    const formatted = formatter(wDay, mDay, month, year, hour, minute, ap);

我们甚至可以为 "formatter" 函数使用命名参数:

    const formatter = (wDay, mDay, month, year, hour, minute, ap) => `${wDay}, the ${mDay} of ${month} ${year} at ${hour}:${minute} ${ap}`;
    const formatted = formatter(wDay, mDay, month, year, hour, minute, ap);

如果你注意到了,上面的JS模板都是回调函数的结果。如果将上面的整个代码块封装在一个预期返回格式化日期的函数中,那么很容易想象如何以同样的方式构建任意的“格式化器”函数,并从外部传入。

简而言之,如果将模板字面量放在回调函数中并使用参数作为替换,就可以重复使用它们。


0

这个可以与{0}、{1}和{}一起使用。

String.prototype.format = function format()
{                                                                                                               
  var msg = this;
  for(var i in arguments)
    msg = msg.replace(/\{\}/,arguments[i]).replace(new RegExp('\\{'+i+'\\}','g'),arguments[i]);
  return msg;
}

0
String.prototype.repeat = function(n) { 
    return new Array(++n).join(this); 
};

String.prototype.pad = function(requiredLength, paddingStr, paddingType) {    
    var n = requiredLength - this.length; 

    if (n) {
        paddingType = paddingType ? paddingType.toLowerCase() : '';
        paddingStr = paddingStr || ' ';
        paddingStr = paddingStr.repeat( Math.ceil(n / paddingStr.length) ).substr(0, n);

        if (paddingType == 'both') {
            n /= 2;
            return paddingStr.substr( 0, Math.ceil(n) ) + this + paddingStr.substr( 0, Math.floor(n) );
        }   

        if (paddingType == 'left') {
            return paddingStr + this;
        }

        return this + paddingStr;
    } 

    return this; 
}; 

// синтаксис аналогичен printf
// 'Привет, %s!'.format('мир') -> "Привет, мир!"
// '%.1s.%.1s. %s'.format('Иван', 'Иванович', 'Иванов') -> "И.И. Иванов"
String.prototype.format = function() {
    var i = 0, 
        params = arguments;

    return this.replace(/%(?:%|(?:(|[+-]+)(|0|'.+?)([1-9]\d*)?(?:\.([1-9]\d*))?)?(s|d|f))/g, function(match, sign, padding, width, precision, type) {
        if (match == '%%') { 
            return '%'; 
        }

        var v = params[i++];

        if (type == 'd') { 
            v = Math.round(v); 
        }
        else if (type == 'f') {
            v = v.toFixed(precision ? precision : 6);
        }

        if (/\+/.test(sign) && v > 0) {
            v = '+' + v;
        }

        v += '';

        if (type != 'f' && precision) {
            v = v.substr(0, precision);
        }

        if (width) {
            v = v.pad(width, padding == '' ? ' ' : padding[0] == "'" ? padding.substr(1) : padding, /-/.test(sign) ? 'right' : 'left'); 
        }

        return v;
    });
};

// this.name = 'Вася';
// console.log( 'Привет, ${name}!'.template(this) );
// "Привет, Вася!"
String.prototype.template = function(context) {
    return this.replace(/\$\{(.*?)\}/g, function(match, name) {
        return context[name];
    });
};

0

0

我开始将 JavaString.format(实际上是 new Formatter().format())移植到 JavaScript。最初的版本可以在以下链接中找到:

https://github.com/RobAu/javascript.string.format

您可以简单地添加JavaScript并调用StringFormat.format("%.2f", [2.4]);等。

请注意,它尚未完成,但欢迎反馈 :)


那么为什么要将其作为可能的解决方案添加呢? - Dragas
1
我的基本要求是目前针对数字的千位分隔符格式 - 它可以很好地处理。 - Rob Audenaerde

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接