在JavaScript中使用String.Format吗?


73

这让我发疯。我相信我也问过同样的问题,但是我再也找不到了(我使用了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;
       }
    );
};



不,我不这么认为。我以为我开始了这篇文章,但我记得看到了关于图书馆的那些建议,但这不是图书馆。
chobo2 2010年

Answers:


72

改编MsAjax字符串中的代码。

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

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

PS-我将所有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: 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);

1
我不知道Javascript可能看起来像C ...:-D。Sky非常棒,感谢您抽出宝贵的时间对此发表评论!
肖恩·维埃拉

2
@Sean,我没有编写代码或注释,我只是从msajax中提取了字符串类,并删除/替换了所有外部依赖项。这为您提供了许多来自.net的非常有用和熟悉的字符串函数。我认为如果您要做某事,那就做对。琐碎的,易碎的弦乐片段是头痛的良方。
Sky Sanders

嗯,我会在几分钟后检查一下。谢谢,但是您必须将所有内容都设为字符串吗?像我可能有一个变量,其中“世界”就像String.Format接受一个对象。也就是有多少占位符,你可以在发送限制我知道以后的String.Format 3个占位你有在一个数组发送。
chobo2

@ chobo2-不,就像在.net中一样,js中的每个对象都有一个.toString函数。通过任何你想要的。与.net不同,arguments对象使您可以轻松接受任意数量的参数,因此只需添加任意数量的参数即可。 String.format("{0},....",true,"aString",new Date(),["a","b"]); 说得通?
Sky Sanders

1
我可以建议将答案stackoverflow.com/a/2534834/21061的URL嵌入脚本吗?能够回到源头很有用
Ian

43

这是我用的。我在实用程序文件中定义了此功能:

  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库获得的:stackoverflow.com/a/1038930/114029
Leniel Maccaferri 2013年

我从此功能中遇到了一些错误
Salvatore Di Fazio

5
@Salvatore Di Fazio:您能详细说明一下这些错误吗?
The_Black_Smurf,2015年

1
您不应该修改不是由您创建的对象(例如,诸如String之类的本机对象)。
马查多

20

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

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:看看它的改写历史,用错误的quot字符重新格式化
vittore 2011年

1
+1谢谢。现在效果很好。在JsFiddle
IsmailS 2011年

@vittore第二种方法很酷,但我无法使其正常工作。它会找到用于检索属性的正确字符串,但未替换它们(至少没有按预期的方式替换它们),例如:jsfiddle.net/9Jpkv/24

1
@gordatron您没有将params作为对象传递。jsfiddle.net/9Jpkv/27
vittore

14

没有第三方功能:

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

有多个参数:

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

嗯,好好看看我发布的内容,因为我不确定确切的功能是什么,但是它正在使用替换。就像我说过的,我记得它使用了json或也许是数组的东西。因此,这可能只是您做事的一种更精细的方法。
chobo2 2010年

1
是的,我不确定您要查找的帖子,这是使用内置JS函数的简单替代方法。
达斯汀·莱恩

4
"Hi {0} {1}. {0}. ".replace('{0}', "John").replace('{1}', "Smith");返回"Hi John Smith. {0}."
IsmailS 2010年

12

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

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

希望这可以帮助!


3

String.Format.NET Framework中的方法具有多个签名。我喜欢原型在其原型中使用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;
    }
};

现在,您可以通过String.Format以下方式使用JavaScript版本:

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

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

谢谢您,此版本非常适合打字稿版本:gist.github.com/fauxtrot/8349c9bd2708a8fa8455
Todd Richardson

2

根据@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;
            };
        }
    }
})();

看起来还不错,但是您一定要对变量“ regexes”进行命名空间,因此它不是全局可用的。
roydukkey

只是将其包装在一个匿名的自执行函数中
Adaptabi

对。我不知道您喜欢的解决方案。我可能已经喜欢上了String.format.cache。尽管如此,每个人自己。谢谢。
roydukkey

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

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

只需制作并使用此功能:

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中字符串格式的想法。


2

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

1

除了您正在修改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的微型模板引擎


+1:在重新阅读了此条目后,肖恩(Sean)击败了我,回答“您的功能已完成此操作”。如果将数组(如Sean的示例所示)传递给格式函数,则索引[0]将映射为“ Bob”。
David

1

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

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

如果您注意到,代码:

var r = o[b];

查看您的参数(o),并在其中使用键值对来解析“替换”


由于您正在定义String函数原型,因此如果页面上的第三方JS尝试执行相同的操作(可能,但可能),您可能会遇到问题。
David

我认为就是这样。如何在我的代码中搜索它,以查看是否正在使用它。就像在VS javascript文件中一样,您无法搜索所有引用,到目前为止,我看到的唯一一个就是Jquery.format,我认为这是不同的。
chobo2 2010年

查找“ .replace”(在每个HTML,PHP / ASP / JSP和JS中)的多文件(如果使用RegEx,则可能需要转义“。”)。误报将应用于JQuery对象(本身不是字符串)。
大卫2010年

1

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

// --------------------------------------------------------------------
// 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())
    };

请享用。


我的直觉使我认为这不会更好,因为它使用了正则表达式替换,但是另一种确定的方法是对两者进行概要分析。现在只能猜测。;)
roydukkey

1

我刚刚开始将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


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

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


1

这是我的两分钱

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


0
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')                 ->     Hello World!

'He{0}{0}o World!'.format('l')            ->     Hello World!

'{0} {1}!'.format('Hello', 'Word')     ->     Hello World!

'{0}!'.format('Hello {1}', 'Word')     ->     Hello World!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.