在JavaScript中使用String.Format的方法?

78
这真的让我疯了。我相信我曾经问过这个完全相同的问题,但我找不到它了(我使用了 Stack Overflow 搜索、Google 搜索、手动搜索了我的帖子和代码进行了搜索)。
我想要的是像 C# String.Format 这样的东西,你可以做类似以下的事情:
string format = String.Format("Hi {0}",name);

当然,这只是针对JavaScript的,有一个人给了我一个简单的答案,它不像jQuery插件或其他什么东西,但我认为你可能做了一些JSON的事情或者类似的东西,它很好用并且使用起来也很简单。

我死都找不到这篇帖子了。

我在我的代码中有这个,但我似乎找不到任何使用它的东西,并且我很确定我用过它几次:

String.prototype.format = function(o)
{
    return this.replace(/{([^{}]*)}/g,
       function(a, b)
       {
           var r = o[b];
           return typeof r === 'string' ? r : a;
       }
    );
};

1
https://dev59.com/YXRB5IYBdhLWcg3weXOX? - Daniel Vassallo
1
或者这个:http://www.geekdaily.net/2007/06/21/cs-stringformat-for-javascript/ - Michael Petrotta
不,我不这么认为。我以为我开始了这篇文章,但我记得看到有关库的建议,但这不是某个库。 - chobo2
19个回答

74

MsAjax字符串中适应代码。

只需删除所有_validateParams代码,就可以实现在JavaScript中完整的.NET字符串类。

好的,我解放了msajax字符串类,删除了所有msajax依赖项。它像.NET字符串类一样完美地工作,包括修剪函数、endsWith / startsWith等。

P.S. - 我保留了所有Visual Studio JavaScript IntelliSense助手和XmlDocs。如果您不使用Visual Studio,则它们是无害的,但您也可以将其删除。

<script src="script/string.js" type="text/javascript"></script>
<script type="text/javascript">
    var a = String.format("Hello {0}!", "world");
    alert(a);

</script>

String.js

// String.js - liberated from MicrosoftAjax.js on 03/28/10 by Sky Sanders
// permalink: https://dev59.com/r3E85IYBdhLWcg3w8IXK#2534834

/*
    Copyright (c) 2009, CodePlex Foundation
    All rights reserved.

    Redistribution and use in source and binary forms, with or without modification, are permitted
    provided that the following conditions are met:

    *   Redistributions of source code must retain the above copyright notice, this list of conditions
        and the following disclaimer.

    *   Redistributions in binary form must reproduce the above copyright notice, this list of conditions
        and the following disclaimer in the documentation and/or other materials provided with the distribution.

    *   Neither the name of CodePlex Foundation nor the names of its contributors may be used to endorse or
        promote products derived from this software without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY EXPRESS OR IMPLIED
    WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
    IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</textarea>
*/

(function(window) {

    $type = String;
    $type.__typeName = 'String';
    $type.__class = true;

    $prototype = $type.prototype;
    $prototype.endsWith = function String$endsWith(suffix) {
        /// <summary>Determines whether the end of this instance matches the specified string.</summary>
        /// <param name="suffix" type="String">A string to compare to.</param>
        /// <returns type="Boolean">true if suffix matches the end of this instance; otherwise, false.</returns>
        return (this.substr(this.length - suffix.length) === suffix);
    }

    $prototype.startsWith = function String$startsWith(prefix) {
        /// <summary >Determines whether the beginning of this instance matches the specified string.</summary>
        /// <param name="prefix" type="String">The String to compare.</param>
        /// <returns type="Boolean">true if prefix matches the beginning of this string; otherwise, false.</returns>
        return (this.substr(0, prefix.length) === prefix);
    }

    $prototype.trim = function String$trim() {
        /// <summary >Removes all leading and trailing white-space characters from the current String object.</summary>
        /// <returns type="String">The string that remains after all white-space characters are removed from the start and end of the current String object.</returns>
        return this.replace(/^\s+|\s+$/g, '');
    }

    $prototype.trimEnd = function String$trimEnd() {
        /// <summary >Removes all trailing white spaces from the current String object.</summary>
        /// <returns type="String">The string that remains after all white-space characters are removed from the end of the current String object.</returns>
        return this.replace(/\s+$/, '');
    }

    $prototype.trimStart = function String$trimStart() {
        /// <summary >Removes all leading white spaces from the current String object.</summary>
        /// <returns type="String">The string that remains after all white-space characters are removed from the start of the current String object.</returns>
        return this.replace(/^\s+/, '');
    }

    $type.format = function String$format(format, args) {
        /// <summary>Replaces the format items in a specified String with the text equivalents of the values of   corresponding object instances. The invariant culture will be used to format dates and numbers.</summary>
        /// <param name="format" type="String">A format string.</param>
        /// <param name="args" parameterArray="true" mayBeNull="true">The objects to format.</param>
        /// <returns type="String">A copy of format in which the format items have been replaced by the   string equivalent of the corresponding instances of object arguments.</returns>
        return String._toFormattedString(false, arguments);
    }

    $type._toFormattedString = function String$_toFormattedString(useLocale, args) {
        var result = '';
        var format = args[0];

        for (var i = 0; ; ) {
            // Find the next opening or closing brace
            var open = format.indexOf('{', i);
            var close = format.indexOf('}', i);
            if ((open < 0) && (close < 0)) {
                // Not found: copy the end of the string and break
                result += format.slice(i);
                break;
            }
            if ((close > 0) && ((close < open) || (open < 0))) {

                if (format.charAt(close + 1) !== '}') {
                    throw new Error('format stringFormatBraceMismatch');
                }

                result += format.slice(i, close + 1);
                i = close + 2;
                continue;
            }

            // Copy the string before the brace
            result += format.slice(i, open);
            i = open + 1;

            // Check for double braces (which display as one and are not arguments)
            if (format.charAt(i) === '{') {
                result += '{';
                i++;
                continue;
            }

            if (close < 0) throw new Error('format stringFormatBraceMismatch');


            // Find the closing brace

            // Get the string between the braces, and split it around the ':' (if any)
            var brace = format.substring(i, close);
            var colonIndex = brace.indexOf(':');
            var argNumber = parseInt((colonIndex < 0) ? brace : brace.substring(0, colonIndex), 10) + 1;

            if (isNaN(argNumber)) throw new Error('format stringFormatInvalid');

            var argFormat = (colonIndex < 0) ? '' : brace.substring(colonIndex + 1);

            var arg = args[argNumber];
            if (typeof (arg) === "undefined" || arg === null) {
                arg = '';
            }

            // If it has a toFormattedString method, call it.  Otherwise, call toString()
            if (arg.toFormattedString) {
                result += arg.toFormattedString(argFormat);
            }
            else if (useLocale && arg.localeFormat) {
                result += arg.localeFormat(argFormat);
            }
            else if (arg.format) {
                result += arg.format(argFormat);
            }
            else
                result += arg.toString();

            i = close + 1;
        }

        return result;
    }

})(window);

2
我不知道JavaScript可以看起来像C语言... :-D。非常好的工作Sky,感谢你抽出时间进行评论! - Sean Vieira
2
@肖恩,我没有编写代码或注释,只是从msajax中取出了字符串类,并删除/替换了所有外部依赖项。这为您提供了许多非常有用且熟悉的来自.net的字符串函数。我认为如果你要做某事,就要做对。琐碎而脆弱的字符串处理片段会让你头痛。 - Sky Sanders
1
我能建议将你的答案的URL https://dev59.com/r3E85IYBdhLWcg3w8IXK#2534834 嵌入到脚本中吗?这样做很有用,可以方便地返回源代码。 - Ian
谢谢,这段代码很有用。但是这个实现没有考虑到将数组作为第二个参数传递给format函数的情况。为了解决这个问题,我改变了_toFormattedString函数的参数为(useLocale, format, args),并且修改了调用它的那一行代码,删除了var format = ...这一行,并且在var argNumber = ...这一行的末尾删除了+1。我可以建议您在下一个用户的答案中反映这一点吗? :) - Iravanchi
链接现在指向一个空的CodePlex存储库 - 他们已经迁移到GitHub - ry8806
显示剩余4条评论

45

这是我使用的方法。我在一个实用工具文件中定义了这个函数:

  String.format = function() {
      var s = arguments[0];
      for (var i = 0; i < arguments.length - 1; i++) {       
          var reg = new RegExp("\\{" + i + "\\}", "gm");             
          s = s.replace(reg, arguments[i + 1]);
      }
      return s;
  }

然后我这样调用:

var greeting = String.format("Hi, {0}", name);

我不记得在哪里找到这个,但它对我非常有用。我喜欢它,因为语法与C#版本相同。


3
你可能是从 Microsoft Ajax 库中获取的:https://dev59.com/pXNA5IYBdhLWcg3wPbSe#1038930。 - Leniel Maccaferri
我从这个函数中得到一些错误。 - Salvatore Di Fazio
5
@Salvatore Di Fazio:您能详细说明一下这些错误吗? - The_Black_Smurf
1
你不应该修改非你创建的对象(例如像String这样的本地对象)。 - Machado
非常适合初学者使用 JavaScript。 - WaXxX333

20
您可以像这样进行一系列替换:
function format(str)
{
    for(i = 1; i < arguments.length; i++)
    {
        str = str.replace('{' + (i - 1) + '}', arguments[i]);
    }
    return str;
}
更好的方法是使用带有函数参数的替换(replace)方法:
function format(str, obj) {
    return str.replace(/\{\s*([^}\s]+)\s*\}/g, function(m, p1, offset, string) {
        return obj[p1]
    })
}
这样,您可以同时提供索引和命名参数:
var arr = ['0000', '1111', '2222']

arr.a = 'aaaa'

str = format(" { 0 } , {1}, { 2}, {a}", arr)
// returns 0000 , 1111, 2222, aaaa

@Ismail:看一下更改历史记录,它被重新格式化了,带有错误的引号字符。 - vittore
1
+1 谢谢。现在运行得很好。在JsFiddle上检查它。 - IsmailS
@vittore 第二种方法非常酷,但我无法让它正常工作。它可以找到正确的字符串来检索属性,但没有替换它们(至少不是按照预期的方式)。例如:http://jsfiddle.net/9Jpkv/24/ - user359135
1
@gordatron,你没有将参数作为对象传递。http://jsfiddle.net/9Jpkv/27/ - vittore

19

没有第三方函数:

string format = "Hi {0}".replace('{0}', name)

使用多个参数:

string format = "Hi {0} {1}".replace('{0}', name).replace('{1}', lastname)

嗯,看看我发布的内容吧,我不确定它确切地做了什么,但它使用了replace。就像我说的,我记得它使用了json或者一些数组之类的东西。所以它可能只是你正在做的事情的更详细的方式。 - chobo2
1
是的,我不确定您要查找哪篇文章,这是一种使用内置JS函数的简单替代方法。 - Dustin Laine
5
"Hi {0} {1}. {0}. ".replace('{0}', "John").replace('{1}', "Smith"); returns "Hi John Smith. {0}." - IsmailS

14

这里是一个使用正则表达式和捕获组的有用字符串格式化函数:

function format (fmtstr) {
  var args = Array.prototype.slice.call(arguments, 1);
  return fmtstr.replace(/\{(\d+)\}/g, function (match, index) {
    return args[index];
  });
}

字符串可以像C# String.Format一样进行格式化:

var str = format('{0}, {1}!', 'Hello', 'world');
console.log(str); // prints "Hello, world!"

即使变量的顺序不同,该格式化程序也会将正确的变量放在正确的位置:

var str = format('{1}, {0}!', 'Hello', 'world');
console.log(str); // prints "world, Hello!"

希望这能帮到你!

4
在ECMAScript 6中使用模板字面量:
var customer = { name: "Foo" }
var card = { amount: 7, product: "Bar", unitprice: 42 }
var message = `Hello ${customer.name},
               want to buy ${card.amount} ${card.product} for
               a total of ${card.amount * card.unitprice} bucks?`

3
来自.NET Framework的String.Format方法有多个签名。我最喜欢的一个在其原型中使用params关键字,即:保留html标签.
public static string Format(
    string format,
    params Object[] args
)

使用此版本,您不仅可以向其传递可变数量的参数,还可以传递数组参数。
因为我喜欢Jeremy提供的简单解决方案,所以我想稍微扩展一下它:
var StringHelpers = {
    format: function(format, args) {
        var i;
        if (args instanceof Array) {
            for (i = 0; i < args.length; i++) {
                format = format.replace(new RegExp('\\{' + i + '\\}', 'gm'), args[i]);
            }
            return format;
        }
        for (i = 0; i < arguments.length - 1; i++) {
            format = format.replace(new RegExp('\\{' + i + '\\}', 'gm'), arguments[i + 1]);
        }
        return format;
    }
};

现在您可以按照以下方式使用JavaScript版本的String.Format
StringHelpers.format("{0}{1}", "a", "b")

StringHelpers.format("{0}{1}", ["a", "b"])

谢谢,这个版本很适合转换成TypeScript版本:https://gist.github.com/fauxtrot/8349c9bd2708a8fa8455 - Todd Richardson

3

只需编写并使用此函数:

function format(str, args) {
   for (i = 0; i < args.length; i++)
      str = str.replace("{" + i + "}", args[i]);
   return str;
}

如果你不想改变 str 参数,在 for 循环之前,将其克隆(复制)到一个新字符串中,并将副本设置为 for 循环的字符串,最后返回副本而不是参数本身。
在C#(Sharp)中,通过调用 String.Clone()可以简单地创建副本,但我不知道JavaScript中如何操作。你可以搜索谷歌或浏览互联网来了解实现方法。
我刚刚给出了自己对JavaScript中字符串格式的看法。

2
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}-{1}'.format('a','b');
// Result: 'a-b'

JSFiddle


2

以下是一种仅使用String.prototype的解决方案:

String.prototype.format = function() {
    var s = this;
    for (var i = 0; i < arguments.length; i++) {       
        var reg = new RegExp("\\{" + i + "\\}", "gm");             
        s = s.replace(reg, arguments[i]);
    }
    return s;
}

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