Entspricht String.format in jQuery


Antworten:


193

Der Quellcode für ASP.NET AJAX steht als Referenz zur Verfügung, sodass Sie ihn auswählen und die Teile, die Sie weiterhin verwenden möchten, in eine separate JS-Datei aufnehmen können. Oder Sie können sie auf jQuery portieren.

Hier ist die Formatierungsfunktion ...

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

Und hier sind die Funktionen "Beenden mit" und "Starten mit Prototypen" ...

String.prototype.endsWith = function (suffix) {
  return (this.substr(this.length - suffix.length) === suffix);
}

String.prototype.startsWith = function(prefix) {
  return (this.substr(0, prefix.length) === prefix);
}

2
Sieht nicht so aus, als ob viel dahinter steckt. Die JavaScript-Version enthält offensichtlich nicht alle ausgefallenen Formatierungsmöglichkeiten für Zahlen. blog.stevex.net/index.php/string-formatting-in-csharp
Nosredna

Wow, ich habe eigentlich schon darüber nachgedacht, aber auch gedacht, dass es aufgrund der Lizenz nicht möglich ist. Ich wusste nicht, dass sie es unter der Microsoft Permissive License veröffentlicht haben. Vielen Dank dafür
Waleed Eissa,

23
Lizenz oder keine Lizenz ... es gibt nur einen richtigen Weg, um etwas so Einfaches zu schreiben
adamJLev

1
Das Erstellen (und anschließende Verwerfen) eines RegEx-Objekts für jedes Argument bei jedem Aufruf des Formats kann den Garbage Collector überfordern.
McKoss

14
Warnung: Dies wird rekursiv formatiert. Wenn Sie dies getan haben {0}{1}, {0}wird es zuerst ersetzt, und dann werden alle Vorkommen {1}sowohl im bereits ersetzten Text als auch im Originalformat ersetzt.
Zenexer

147

Dies ist eine schnellere / einfachere (und prototypische) Variante der von Josh veröffentlichten Funktion:

String.prototype.format = String.prototype.f = function() {
    var s = this,
        i = arguments.length;

    while (i--) {
        s = s.replace(new RegExp('\\{' + i + '\\}', 'gm'), arguments[i]);
    }
    return s;
};

Verwendung:

'Added {0} by {1} to your collection'.f(title, artist)
'Your balance is {0} USD'.f(77.7) 

Ich benutze das so oft, dass ich es nur als Alias ​​bezeichnet habe f, aber Sie können auch das ausführlichere verwenden format. z.B'Hello {0}!'.format(name)


1
Mit modernen Browsern gibt es noch einfacher Ansätze: stackoverflow.com/a/41052964/120296
david

3
@david Template String sind eigentlich NICHT das Gleiche. Sie sind syntaktischer Zucker für die Verkettung von Zeichenfolgen, was nett ist, aber nicht mit der Formatierung identisch ist. Sie werden sofort ausgeführt, daher müssen die Ersetzungen zum Zeitpunkt der Definition im Geltungsbereich sein. Sie können sie daher nicht in einer Textdatei oder Datenbank speichern. Tatsächlich besteht die einzige Möglichkeit, sie irgendwo zu speichern, darin, sie in eine Funktion zu integrieren. Eine formatierte Zeichenfolgenfunktion ersetzt Positionen, bei denen der Name der Variablen keine Rolle spielt.
Krowe2

131

Viele der oben genannten Funktionen (außer der von Julian Jelfs) enthalten den folgenden Fehler:

js> '{0} {0} {1} {2}'.format(3.14, 'a{2}bc', 'foo');
3.14 3.14 afoobc foo

Oder für die Varianten, die ab dem Ende der Argumentliste rückwärts zählen:

js> '{0} {0} {1} {2}'.format(3.14, 'a{0}bc', 'foo');
3.14 3.14 a3.14bc foo

Hier ist eine korrekte Funktion. Es ist eine prototypische Variante von Julian Jelfs 'Code, die ich etwas enger gemacht habe:

String.prototype.format = function () {
  var args = arguments;
  return this.replace(/\{(\d+)\}/g, function (m, n) { return args[n]; });
};

Und hier ist eine etwas fortgeschrittenere Version derselben, mit der Sie Zahnspangen entkommen können, indem Sie sie verdoppeln:

String.prototype.format = function () {
  var args = arguments;
  return this.replace(/\{\{|\}\}|\{(\d+)\}/g, function (m, n) {
    if (m == "{{") { return "{"; }
    if (m == "}}") { return "}"; }
    return args[n];
  });
};

Das funktioniert richtig:

js> '{0} {{0}} {{{0}}} {1} {2}'.format(3.14, 'a{2}bc', 'foo');
3.14 {0} {3.14} a{2}bc foo

Hier ist eine weitere gute Implementierung von Blair Mitchelmore mit einer Reihe netter zusätzlicher Funktionen: https://web.archive.org/web/20120315214858/http://blairmitchelmore.com/javascript/string.format


Und noch eine, die ich mir nicht allzu genau angesehen habe, die aber Formate wie {0: + $ #, 0.00; - $ #, 0.00; 0} zu implementieren scheint: masterdata.dyndns.org/r/string_format_for_javascript
gpvos

Ooh, und eine, die das Python-Interpolationsformat verwendet: code.google.com/p/jquery-utils/wiki/…
gpvos


Hinweis: Mit der Antwort von ianj an anderer Stelle auf dieser Seite können Sie benannte anstelle von numerischen Parametern verwenden. Wenn Sie seine Methode in eine Methode ändern, die Prototypen verwendet, müssen Sie den zweiten Parameter in die Funktion slot.call von 1 auf 0
ändern

48

Es wurde eine Formatierungsfunktion erstellt, die entweder eine Sammlung oder ein Array als Argumente verwendet

Verwendung:

format("i can speak {language} since i was {age}",{language:'javascript',age:10});

format("i can speak {0} since i was {1}",'javascript',10});

Code:

var format = function (str, col) {
    col = typeof col === 'object' ? col : Array.prototype.slice.call(arguments, 1);

    return str.replace(/\{\{|\}\}|\{(\w+)\}/g, function (m, n) {
        if (m == "{{") { return "{"; }
        if (m == "}}") { return "}"; }
        return col[n];
    });
};

5
Schön, alles was fehlt ist: String.prototype.format = function (col) {Rückgabeformat (this, col);}
Erik

10
Ich ziehe es vor, den String nicht zu verlängern
ianj

3
Es gibt einen kleinen Tippfehler in der Verwendung: Die zweite Zeile sollte sein: Format ("Ich kann {0} sprechen, da ich {1} war", 'Javascript', 10);
Guillaume Gendre

Warum nicht lieber den String verlängern String.prototype?
Kiquenet

36

Es gibt eine (etwas) offizielle Option: jQuery.validator.format .

Kommt mit jQuery Validation Plugin 1.6 (mindestens).
Ganz ähnlich wie String.Formatin .NET.

Bearbeiten Behobener defekter Link.



13

Obwohl nicht genau das, wonach der Q gefragt hat, habe ich einen erstellt, der ähnlich ist, aber benannte Platzhalter anstelle von nummerierten verwendet. Ich persönlich bevorzuge es, benannte Argumente zu haben und nur ein Objekt als Argument zu senden (ausführlicher, aber einfacher zu pflegen).

String.prototype.format = function (args) {
    var newStr = this;
    for (var key in args) {
        newStr = newStr.replace('{' + key + '}', args[key]);
    }
    return newStr;
}

Hier ist ein Anwendungsbeispiel ...

alert("Hello {name}".format({ name: 'World' }));

8

Mit einem modernen Browser, der EcmaScript 2015 (ES6) unterstützt, können Sie Template Strings genießen . Anstatt zu formatieren, können Sie den Variablenwert direkt einfügen:

var name = "Waleed";
var message = `Hello ${name}!`;

Beachten Sie, dass die Vorlagenzeichenfolge mit Back-Ticks (`) geschrieben werden muss.


6

Keine der bisher präsentierten Antworten hat keine offensichtliche Optimierung der Verwendung von Enclosure zum einmaligen Initialisieren und Speichern regulärer Ausdrücke für spätere Verwendungen.

// DBJ.ORG string.format function
// usage:   "{0} means 'zero'".format("nula") 
// returns: "nula means 'zero'"
// place holders must be in a range 0-99.
// if no argument given for the placeholder, 
// no replacement will be done, so
// "oops {99}".format("!")
// returns the input
// same placeholders will be all replaced 
// with the same argument :
// "oops {0}{0}".format("!","?")
// returns "oops !!"
//
if ("function" != typeof "".format) 
// add format() if one does not exist already
  String.prototype.format = (function() {
    var rx1 = /\{(\d|\d\d)\}/g, rx2 = /\d+/ ;
    return function() {
        var args = arguments;
        return this.replace(rx1, function($0) {
            var idx = 1 * $0.match(rx2)[0];
            return args[idx] !== undefined ? args[idx] : (args[idx] === "" ? "" : $0);
        });
    }
}());

alert("{0},{0},{{0}}!".format("{X}"));

Außerdem berücksichtigt keines der Beispiele die Implementierung von format (), falls bereits eines vorhanden ist.


2
rx2 ist unnötig, siehe meine Implementierung; Sie haben (Klammern) in rx1, aber verwenden Sie nicht den Wert, den sie an die innere Funktion übergeben. Ich denke auch, dass dies eine offensichtliche Optimierung in der Javascript-Engine ist . Sind Sie sicher, dass moderne Browser diese Optimierung nicht bereits hinter den Kulissen durchführen? Perl hat dies 1990 getan. Sie haben Recht, dass die Funktion mit einem Wrapper versehen sein sollte, um zu überprüfen, ob sie bereits implementiert ist.
GPVOS

1
Auch der Test auf (args [idx] === "") erscheint mir überflüssig: Er wird bereits vom ersten Test in dieser Zeile abgedeckt, weil undefiniert! == "".
GPVOS

4

Hier ist meins:

String.format = function(tokenised){
        var args = arguments;
        return tokenised.replace(/{[0-9]}/g, function(matched){
            matched = matched.replace(/[{}]/g, "");
            return args[parseInt(matched)+1];             
        });
    }

Nicht kugelsicher, funktioniert aber, wenn Sie es vernünftig verwenden.


4

Weit nach der Spätsaison habe ich mir nur die Antworten angesehen und meine Tuppence wert:

Verwendung:

var one = strFormat('"{0}" is not {1}', 'aalert', 'defined');
var two = strFormat('{0} {0} {1} {2}', 3.14, 'a{2}bc', 'foo');

Methode:

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

Ergebnis:

"aalert" is not defined
3.14 3.14 a{2}bc foo

3

Jetzt können Sie Vorlagenliterale verwenden :

var w = "the Word";
var num1 = 2;
var num2 = 3;

var long_multiline_string = `This is very long
multiline templete string. Putting somthing here:
${w}
I can even use expresion interpolation:
Two add three = ${num1 + num2}
or use Tagged template literals
You need to enclose string with the back-tick (\` \`)`;

console.log(long_multiline_string);


3
Ich war begeistert von Vorlagenliteralen, bis ich sah, dass sie nur funktionieren, wenn die Zeichenfolge neben den Ersetzungsvariablen definiert ist. Für mich macht das sie ziemlich nutzlos; Aus dem einen oder anderen Grund werden die meisten meiner Zeichenfolgen getrennt von dem Code definiert, der sie auffüllt / verwendet.
Stein

2

Hier ist meine Version, die in der Lage ist, '{' zu entkommen und diese nicht zugewiesenen Platzhalter zu bereinigen.

function getStringFormatPlaceHolderRegEx(placeHolderIndex) {
    return new RegExp('({)?\\{' + placeHolderIndex + '\\}(?!})', 'gm')
}

function cleanStringFormatResult(txt) {
    if (txt == null) return "";

    return txt.replace(getStringFormatPlaceHolderRegEx("\\d+"), "");
}

String.prototype.format = function () {
    var txt = this.toString();
    for (var i = 0; i < arguments.length; i++) {
        var exp = getStringFormatPlaceHolderRegEx(i);
        txt = txt.replace(exp, (arguments[i] == null ? "" : arguments[i]));
    }
    return cleanStringFormatResult(txt);
}
String.format = function () {
    var s = arguments[0];
    if (s == null) return "";

    for (var i = 0; i < arguments.length - 1; i++) {
        var reg = getStringFormatPlaceHolderRegEx(i);
        s = s.replace(reg, (arguments[i + 1] == null ? "" : arguments[i + 1]));
    }
    return cleanStringFormatResult(s);
}

2

Die folgende Antwort ist wahrscheinlich die effizienteste, hat jedoch den Vorbehalt, dass sie nur für 1: 1-Zuordnungen von Argumenten geeignet ist. Dies verwendet die schnellste Methode zum Verketten von Zeichenfolgen (ähnlich einem Stringbuilder: Array von Zeichenfolgen, verbunden). Dies ist mein eigener Code. Benötigt wahrscheinlich ein besseres Trennzeichen.

String.format = function(str, args)
{
    var t = str.split('~');
    var sb = [t[0]];
    for(var i = 0; i < args.length; i++){
        sb.push(args[i]);
        sb.push(t[i+1]);
    }
    return sb.join("");
}

Verwenden Sie es wie:

alert(String.format("<a href='~'>~</a>", ["one", "two"]));

2
Akzeptierte Antwort ist die beste Antwort. Ich gebe eine eindeutige Antwort, die in Szenarien nützlich ist, in denen Sie jede mögliche Effizienz (lange Schleifen) einschränken möchten und eine 1: 1-Zuordnung von Argumenten haben. Effizienteres cuz replace () und neues Regex () sowie das Ausführen des Regex verwenden definitiv mehr CPU-Zyklen als Single Split ().
Skychan

Keine Notwendigkeit für -1. Nein, es ist nicht allgemein anwendbar, aber er hat Recht, das wäre etwas effizienter. Nun an den Autor eine Architekturfrage: Welche Art von Anwendung würde mit einem so großen Datensatz auf dem Client umgehen, dass diese Art der Optimierung erforderlich wäre?
Michael Blackburn

Guter Punkt Michael Blackburn. Die meisten Situationen sind wahrscheinlich in Ordnung. In meinem Fall hatte ich es mit einem guten Datenblock zu tun (Produktvariationen innerhalb einer Produktgruppe, also möglicherweise Hunderte von Varianten), und ich bin der Meinung, dass Benutzer normalerweise viele Browser-Registerkarten geöffnet haben und jede Website dazu neigt, viel CPU zu verbrauchen Ich habe diese Implementierung vorgezogen, um eine hohe Effizienz aufrechtzuerhalten.
Skychan

2

Dies verstößt gegen das DRY-Prinzip, ist jedoch eine präzise Lösung:

var button = '<a href="{link}" class="btn">{text}</a>';
button = button.replace('{text}','Authorize on GitHub').replace('{link}', authorizeUrl);

0
<html>
<body>
<script type="text/javascript">
   var str="http://xyz.html?ID={0}&TId={1}&STId={2}&RId={3},14,480,3,38";
   document.write(FormatString(str));
   function FormatString(str) {
      var args = str.split(',');
      for (var i = 0; i < args.length; i++) {
         var reg = new RegExp("\\{" + i + "\\}", "");             
         args[0]=args[0].replace(reg, args [i+1]);
      }
      return args[0];
   }
</script>
</body>
</html>

Dies ist für URIs in Ordnung, aber für die allgemeine Verwendung ist es sehr spröde, wenn eine Zeichenfolge sowohl das Format als auch die Komponenten enthält. Was ist, wenn Ihre Zeichenfolge Kommas enthält?
Michael Blackburn

0

Ich konnte Josh Stodolas Antwort nicht zur Arbeit bringen, aber das Folgende funktionierte für mich. Beachten Sie die Spezifikation von prototype. (Getestet auf IE, FF, Chrome und Safari.):

String.prototype.format = function() {
    var s = this;
    if(t.length - 1 != args.length){
        alert("String.format(): Incorrect number of arguments");
    }
    for (var i = 0; i < arguments.length; i++) {       
        var reg = new RegExp("\\{" + i + "\\}", "gm");
        s = s.replace(reg, arguments[i]);
    }
    return s;
}

ssollte wirklich ein sein Klon von thisum nicht eine destruktiven Methode zu sein, aber es ist nicht wirklich notwendig.


Es ist keine destruktive Methode. Wenn s mit dem Rückgabewert von s.replace () neu zugewiesen wird, bleibt dies unberührt.
GPVOS

0

Hier ist die TypeScript-Version, die die großartige Antwort von adamJLev oben erweitert :

// Extending String prototype
interface String {
    format(...params: any[]): string;
}

// Variable number of params, mimicking C# params keyword
// params type is set to any so consumer can pass number
// or string, might be a better way to constraint types to
// string and number only using generic?
String.prototype.format = function (...params: any[]) {
    var s = this,
        i = params.length;

    while (i--) {
        s = s.replace(new RegExp('\\{' + i + '\\}', 'gm'), params[i]);
    }

    return s;
};

0

Ich habe einen Plunker, der ihn dem String-Prototyp hinzufügt : string.format Er ist nicht nur so kurz wie einige der anderen Beispiele, sondern auch viel flexibler.

Die Verwendung ähnelt der c # -Version:

var str2 = "Meet you on {0}, ask for {1}";
var result2 = str2.format("Friday", "Suzy"); 
//result: Meet you on Friday, ask for Suzy
//NB: also accepts an array

Unterstützung für die Verwendung von Namen und Objekteigenschaften hinzugefügt

var str1 = "Meet you on {day}, ask for {Person}";
var result1 = str1.format({day: "Thursday", person: "Frank"}); 
//result: Meet you on Thursday, ask for Frank

0

Sie können das Array auch mit solchen Ersetzungen schließen.

var url = '/getElement/_/_/_'.replace(/_/g, (_ => this.ar[this.i++]).bind({ar: ["invoice", "id", 1337],i: 0}))
> '/getElement/invoice/id/1337

oder du kannst es versuchen bind

'/getElement/_/_/_'.replace(/_/g, (function(_) {return this.ar[this.i++];}).bind({ar: ["invoice", "id", 1337],i: 0}))
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.