【问题标题】:Use of String.Format in JavaScript?在 JavaScript 中使用 String.Format?
【发布时间】:2010-03-28 22:17:56
【问题描述】:

这让我发疯了。我相信我问过这个完全相同的问题,但我再也找不到它了(我使用 StackOverflow 搜索、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;
       }
    );
};

【问题讨论】:

标签: c# .net javascript


【解决方案1】:

改编来自MsAjax string的代码。

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

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

附: - 我保留了所有 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>

字符串.js

// String.js - liberated from MicrosoftAjax.js on 03/28/10 by Sky Sanders
// permalink: http://stackoverflow.com/a/2534834/2343

/*
    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);

【讨论】:

  • 我不知道 Javascript 有可能看起来像 C ... :-D。非常好的工作 Sky,感谢您抽出宝贵时间发表评论!
  • @Sean,我没有编写代码或 cmets,我只是从 msajax 中获取了字符串类并删除/替换了所有外部依赖项。这为您提供了许多来自 .net 的非常有用且熟悉的字符串函数。我想如果你要做某事,那就做对吧。琐碎而脆弱的字符串 munging sn-ps 会让人头疼。
  • 嗯,我会在几分钟后检查一下。谢谢,但你必须把所有东西都变成一个字符串吗?就像我可以有一个变量,其中“世界”就像 String.Format 接受一个对象一样。您可以发送多少个占位符也有限制。我知道 String.Format 在您必须发送数组中的 3 个占位符之后。
  • @chobo2 - 不,就像在 .net 中一样,js 中的每个对象都有一个 .toString 函数。传递你想要的任何东西。与 .net 不同,arguments 对象可以很容易地接受任意数量的参数,所以只要你想添加多少就添加多少。 String.format("{0},....",true,"aString",new Date(),["a","b"]); 有意义吗?
  • 我可以建议将您的答案stackoverflow.com/a/2534834/21061 的 URL 嵌入到脚本中吗?能够回到源头很有用
【解决方案2】:

这是我使用的。我在实用程序文件中定义了这个函数:

  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# 版本相同。

【讨论】:

  • 您可能从 Microsoft Ajax 库中获得它:stackoverflow.com/a/1038930/114029
  • 我从这个函数中得到了一些错误
  • @Salvatore Di Fazio:你能详细说明一下这些错误吗?
  • 你不应该修改不是你创建的对象(例如,像 String 这样的原生对象)。
【解决方案3】:

您可以像这样进行一系列替换:

function format(str)
{
    for(i = 1; i < arguments.length; i++)
    {
        str = str.replace('{' + (i - 1) + '}', arguments[i]);
    }
    return str;
}

更好的方法是使用函数参数替换:

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: 看看用错误的引号重新格式化的更改历史
  • +1 谢谢。现在效果很好。在JsFiddle 上查看
  • @vittore 第二种方法很酷,但我无法让它工作。它找到了用于检索属性的正确字符串,但没有替换它们(至少不是预期的),例如:jsfiddle.net/9Jpkv/24
  • @gordatron 您没有将参数作为对象传递。 jsfiddle.net/9Jpkv/27
【解决方案4】:

无第三方功能:

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

有多个参数:

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

【讨论】:

  • 嗯,看看我发布的内容,因为我不确定它到底是做什么的,但它正在使用替换。就像我说的,我记得它使用了 json 或者也许还有一些东西。因此,这可能只是您所做工作的一种更精细的方式。
  • 是的,我不确定你在找什么帖子,这是一个使用内置 JS 函数的简单替代方案。
  • "Hi {0} {1}. {0}. ".replace('{0}', "John").replace('{1}', "Smith"); 返回"Hi John Smith. {0}."
【解决方案5】:

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

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

希望这会有所帮助!

【讨论】:

    【解决方案6】:

    在 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?`
    

    【讨论】:

      【解决方案7】:

      .NET Framework 中的String.Format 方法具有multiple signatures。我喜欢的the most 在其原型中使用了params 关键字,即:

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

      【讨论】:

      【解决方案8】:

      只需制作并使用此功能:

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

      如果您不想更改 str 参数,则在 for 循环之前,将其克隆(复制)到新字符串(制作 str),并在for循环中设置副本,最后返回它而不是参数本身。

      在 C# (Sharp) 中,只需调用String.Clone() 即可轻松创建副本,但我不知道如何在 JavaScript 中,但您可以在 Google 上搜索或在 Internet 上冲浪并学习方法。

      我刚刚告诉了你我对 JavaScript 中字符串格式的想法。

      【讨论】:

        【解决方案9】:

        基于@roydukkey 的回答,针对运行时进行了更多优化(它缓存了正则表达式):

        (function () {
            if (!String.prototype.format) {
                var regexes = {};
                String.prototype.format = function (parameters) {
                    for (var formatMessage = this, args = arguments, i = args.length; --i >= 0;)
                        formatMessage = formatMessage.replace(regexes[i] || (regexes[i] = RegExp("\\{" + (i) + "\\}", "gm")), args[i]);
                    return formatMessage;
                };
                if (!String.format) {
                    String.format = function (formatMessage, params) {
                        for (var args = arguments, i = args.length; --i;)
                            formatMessage = formatMessage.replace(regexes[i - 1] || (regexes[i - 1] = RegExp("\\{" + (i - 1) + "\\}", "gm")), args[i]);
                        return formatMessage;
                    };
                }
            }
        })();
        

        【讨论】:

        • 看起来不错,但您肯定应该命名变量“正则表达式”,因此它不是全局可用的。
        • 只是将它包装在一个匿名的自执行函数中
        • 对。我不知道您喜欢的解决方案。我可能会选择String.format.cache 之类的东西。尽管如此,对每个人来说都是他自己的。谢谢。
        【解决方案10】:

        这是一个仅适用于 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;
        }
        

        【讨论】:

          【解决方案11】:
          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

          【讨论】:

            【解决方案12】:

            除了您正在修改 String 原型之外,您提供的函数没有任何问题。你会这样使用它:

            "Hello {0},".format(["Bob"]);
            

            如果你想把它作为一个独立的函数,你可以稍微改变一下:

            function format(string, object) {
                return string.replace(/{([^{}]*)}/g,
                   function(match, group_match)
                   {
                       var data = object[group_match];
                       return typeof data === 'string' ? data : match;
                   }
                );
            }
            

            维托雷的方法也不错;他的函数被调用,每个额外的格式化选项都作为参数传入,而你的函数需要一个对象。

            这实际上是 John Resig 的 micro-templating engine

            【讨论】:

            • +1:重读这篇文章后,Sean 击败了我,给出了“你的函数已经这样做了”的答案。如果您将数组(如 Sean 的示例所示)传递给格式函数,索引 [0] 将映射到“Bob”。
            【解决方案13】:

            您的函数已经将 JSON 对象作为参数:

            string format = "Hi {foo}".replace({
                "foo": "bar",
                "fizz": "buzz"
            });
            

            如果你注意到,代码:

            var r = o[b];
            

            查看您的参数 (o) 并使用其中的键值对来解决“替换”问题

            【讨论】:

            • 由于您正在定义一个字符串函数原型,如果您页面上的第 3 方 JS 尝试做同样的事情,您可能会遇到问题(不太可能但可能)。
            • 我想就是这样。我如何在我的代码中搜索它以查看我是否正在使用它。就像在 VS javascript 文件中一样,您无法搜索所有参考资料,到目前为止我看到的唯一参考资料是 Jquery.format,我认为这是不同的。
            • 多文件查找(在每个 HTML、PHP/ASP/JSP 和 JS 中)用于“.replace”(如果您正在执行正则表达式,您可能需要转义“.”)。误报将应用于 JQuery 对象(它们本身不是字符串)。
            【解决方案14】:

            这是一个允许原型和函数选项的解决方案。

            // --------------------------------------------------------------------
            // Add prototype for 'String.format' which is c# equivalent
            //
            // String.format("{0} i{2}a night{1}", "This", "mare", "s ");
            // "{0} i{2}a night{1}".format("This", "mare", "s ");
            // --------------------------------------------------------------------
            
            if(!String.format)
                String.format = function(){
                    for (var i = 0, args = arguments; i < args.length - 1; i++)
                        args[0] = args[0].replace("{" + i + "}", args[i + 1]);
                    return args[0];
                };
            if(!String.prototype.format && String.format)
                String.prototype.format = function(){
                    var args = Array.prototype.slice.call(arguments).reverse();
                    args.push(this);
                    return String.format.apply(this, args.reverse())
                };
            

            享受吧。

            【讨论】:

            • 我的直觉让我认为它不会更好,因为它使用的是正则表达式替换,但另一种确定的方法是分析两者。目前只能猜测。 ;)
            【解决方案15】:

            我刚刚开始将 Java 的 String.format() 移植到 JavaScript。您可能会发现它也很有用。

            它支持这样的基本内容:

            StringFormat.format("Hi %s, I like %s", ["Rob", "icecream"]);
            

            这会导致

            Hi Rob, I like icecream.
            

            还有更高级的数字格式和日期格式,例如:

            StringFormat.format("Duke's Birthday: %1$tA %1$te %1$tB, %1$tY", [new Date("2014-12-16")]);
            
            Duke's Birthday: Tuesday 16 December, 2014
            

            请参阅示例以了解更多信息。

            请看这里:https://github.com/RobAu/javascript.string.format

            【讨论】:

              【解决方案16】:
              //Add "format" method to the string class
              //supports:  "Welcome {0}. You are the first person named {0}".format("David");
              //       and "First Name:{} Last name:{}".format("David","Wazy");
              //       and "Value:{} size:{0} shape:{1} weight:{}".format(value, size, shape, weight)
              String.prototype.format = function () {
                  var content = this;
                  for (var i = 0; i < arguments.length; i++) {
                      var target = '{' + i + '}';
                      content=content.split(target).join(String(arguments[i]))
                      content = content.replace("{}", String(arguments[i]));
                  }
                  return content;
              }
              alert("I {} this is what {2} want and {} works for {2}!".format("hope","it","you"))
              

              您可以使用此功能混合和匹配使用位置和“命名”替换位置。

              【讨论】:

                【解决方案17】:

                这是我的two cents

                function stringFormat(str) {
                  if (str !== undefined && str !== null) {
                    str = String(str);
                    if (str.trim() !== "") {
                      var args = arguments;
                      return str.replace(/(\{[^}]+\})/g, function(match) {
                        var n = +match.slice(1, -1);
                        if (n >= 0 && n < args.length - 1) {
                          var a = args[n + 1];
                          return (a !== undefined && a !== null) ? String(a) : "";
                        }
                        return match;
                      });
                    }
                  }
                  return "";
                }
                
                alert(stringFormat("{1}, {0}. You're looking {2} today.",
                  "Dave", "Hello", Math.random() > 0.5 ? "well" : "good"));
                

                【讨论】:

                  【解决方案18】:

                  使用sprintf

                  在这里您有一个link,您可以在其中找到该库的功能。

                  【讨论】:

                    【解决方案19】:
                    String.prototype.format = function () {
                        var formatted = this;
                        for (var arg in arguments) {
                            formatted = formatted.split('{' + arg + '}').join(arguments[arg]);
                        }
                        return formatted;
                    };
                    

                    用法:

                    'Hello {0}!'.format('Word')               -&gt;     Hello World!

                    'He{0}{0}o World!'.format('l')        -&gt;   Hello World!

                    '{0} {1}!'.format('Hello', 'Word')   -&gt;   Hello World!

                    '{0}!'.format('Hello {1}', 'Word')   -&gt;   Hello World!

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 2012-10-16
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2010-10-11
                      相关资源
                      最近更新 更多