Equivalente di String.format in jQuery


Risposte:


193

Il codice sorgente per ASP.NET AJAX è disponibile come riferimento, quindi è possibile selezionarlo e includere le parti che si desidera continuare a utilizzare in un file JS separato. Oppure, puoi portarli su jQuery.

Ecco la funzione di formattazione ...

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

Ed ecco le estremità Con e inizia Con funzioni prototipo ...

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
Non sembra che ci sia molto da fare. La versione JavaScript non ha tutte le fantasiose funzionalità di formattazione dei numeri, ovviamente. blog.stevex.net/index.php/string-formatting-in-csharp
Nosredna

Wow, in realtà ci ho già pensato, ma ho anche pensato che non fosse possibile a causa della licenza, non sapevo di averlo rilasciato sotto la Licenza Permissiva Microsoft, grazie mille per questo
Waleed Eissa,

23
Licenza o nessuna licenza .. c'è solo un modo giusto per scrivere qualcosa di così semplice
adamJLev

1
Costruire (e quindi scartare) un oggetto RegEx per ogni argomento ogni volta che viene chiamato il formato potrebbe sovraccaricare il Garbage Collector.
mckoss,

14
Attenzione: questo verrà formattato in modo ricorsivo: quindi, se lo hai {0}{1}, {0}verrà sostituito per primo, quindi verranno sostituite tutte le occorrenze {1}sia nel testo già sostituito sia nel formato originale.
Zenexer,

147

Questa è una variazione più rapida / semplice (e prototipica) della funzione pubblicata da Josh:

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

Uso:

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

Lo uso così tanto che lo aliasavo solo f, ma puoi anche usare il più dettagliato format. per esempio'Hello {0}!'.format(name)


1
Con i browser moderni ci sono approcci ancora più semplici: stackoverflow.com/a/41052964/120296
david

3
Le stringhe di template @david NON sono affatto la stessa cosa. Sono zucchero sintattico per la concatenazione di stringhe, che è carino ma non è la stessa formattazione. Funzionano all'istante, quindi i rimpiazzi devono rientrare nel campo di definizione. Per questo motivo non è possibile memorizzarli in un file di testo o in un database. In effetti, l'unico modo per memorizzarli ovunque è metterli in una funzione. Una funzione stringa formattata accetta sostituzioni posizionali a cui non interessa il nome della variabile.
krowe2,

131

Molte delle funzioni sopra (eccetto quelle di Julian Jelfs) contengono il seguente errore:

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

Oppure, per le varianti che contano all'indietro dalla fine dell'elenco degli argomenti:

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

Ecco una funzione corretta. È una variante prototipo del codice di Julian Jelfs, che ho reso un po 'più stretto:

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

Ed ecco una versione leggermente più avanzata della stessa, che ti permette di sfuggire alle parentesi raddoppiandole:

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

Questo funziona correttamente:

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

Ecco un'altra buona implementazione di Blair Mitchelmore, con un sacco di belle funzioni extra: https://web.archive.org/web/20120315214858/http://blairmitchelmore.com/javascript/string.format


E un altro, che non ho guardato troppo da vicino, ma che sembra implementare formati come {0: + $ #, 0.00; - $ #, 0.00; 0}: masterdata.dyndns.org/r/string_format_for_javascript
gpvos

Ooh, e uno che utilizza il formato di interpolazione Python: code.google.com/p/jquery-utils/wiki/…
gpvos

L'implementazione formato ho citato due commenti fino si è spostato a masterdata.se/r/string_format_for_javascript
gpvos

Nota: la risposta di ianj altrove in questa pagina consente di utilizzare parametri nominati anziché numerici. Se cambi il suo metodo in uno che utilizza prototipi, dovrai modificare il secondo parametro nella funzione slice.call da 1 a 0.
gpvos

48

Ha creato una funzione di formato che accetta una raccolta o una matrice come argomenti

Uso:

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

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

Codice:

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
Bello, manca solo: String.prototype.format = function (col) {formato di ritorno (this, col);}
Erik

10
preferisco non estendere la stringa
ianj

3
c'è un piccolo errore di battitura nell'uso: la seconda riga dovrebbe essere: format ("posso parlare {0} da quando ero {1}", "javascript", 10);
Guillaume Gendre,

Perché non preferisci estendere la stringa usando String.prototype?
Kiquenet,

36

Esiste un'opzione (in qualche modo) ufficiale: jQuery.validator.format .

Viene fornito con jQuery Validation Plugin 1.6 (almeno).
Abbastanza simile a quello String.Formattrovato in .NET.

Modifica Collegamento interrotto fisso.



13

Sebbene non sia esattamente quello che chiedeva la Q, ne ho costruito uno simile ma che utilizza segnaposto nominati anziché numerati. Personalmente preferisco aver chiamato argomenti e inviare semplicemente un oggetto come argomento (più dettagliato, ma più facile da mantenere).

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

Ecco un esempio di utilizzo ...

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

8

Utilizzando un browser moderno, che supporta EcmaScript 2015 (ES6), è possibile utilizzare Template Strings . Invece di formattare, puoi inserire direttamente il valore della variabile al suo interno:

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

Nota che la stringa del modello deve essere scritta usando i segni di spunta (`).


6

Nessuna delle risposte presentate finora non ha alcuna ovvia ottimizzazione dell'uso del contenitore per inizializzare una volta e memorizzare espressioni regolari, per usi successivi.

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

Inoltre, nessuno degli esempi rispetta l'implementazione di format () se ne esiste già uno.


2
rx2 non è necessario, vedi la mia implementazione; hai (parentesi) in rx1, ma non usare il valore che passano alla funzione interna. Inoltre, penso che questa sia un'ovvia ottimizzazione da fare nel motore Javascript . Sei sicuro che i browser moderni non facciano già questa ottimizzazione dietro le quinte? Perl l'ha fatto nel 1990. Hai ragione a dire che dovrebbe esserci un wrapper attorno alla funzione per verificare se è già implementata.
gpvos,

1
Inoltre, il test su (args [idx] === "") mi sembra superfluo: è già coperto dal primo test su quella riga, perché indefinito! == "".
gpvos,

4

Ecco il mio:

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

Non a prova di proiettile ma funziona se lo usi in modo ragionevole.


4

Oltre la fine della stagione, ma ho appena esaminato le risposte fornite e valgo il mio sostegno:

Uso:

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

Metodo:

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

Risultato:

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

3

Ora puoi usare Letterali modello :

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
Ero entusiasta dei letterali template fino a quando non ho visto che funzionano solo quando la stringa è definita accanto alle variabili di sostituzione. Per me questo li rende praticamente inutili; per una ragione o per l'altra la maggior parte delle mie stringhe sono definite separatamente dal codice che le popola / le usa.
pietra,

2

Ecco la mia versione che è in grado di sfuggire a "{" e ripulire i segnaposti non assegnati.

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

La seguente risposta è probabilmente la più efficace, ma ha la premessa di essere adatta solo per 1 a 1 mapping di argomenti. Questo utilizza il modo più veloce di concatenare le stringhe (simile a un costruttore di stringhe: array di stringhe, unito). Questo è il mio codice Probabilmente ha bisogno di un separatore migliore però.

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

Usalo come:

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

2
La risposta accettata è la risposta migliore. Sto dando una risposta unica che è utile in scenari in cui vuoi spremere ogni bit di efficienza possibile (loop lunghi) e hai una mappatura 1: 1 di args. Cuz sostituisce () più efficiente e il nuovo Regex () insieme all'esecuzione del regex utilizza sicuramente più cicli della CPU rispetto al singolo split ().
Skychan,

Non è necessario -1. No, non è ampiamente applicabile, ma ha ragione, questo sarebbe leggermente più efficiente. Ora, per l'autore, una domanda sull'architettura: che tipo di applicazione avrebbe a che fare con un set di dati così grande sul client da richiedere questo tipo di ottimizzazione?
Michael Blackburn,

Buon punto Michael Blackburn. La maggior parte delle situazioni probabilmente va bene. Nel mio caso avevo a che fare con una buona porzione di dati (variazioni di prodotto all'interno di un gruppo di prodotti, quindi probabilmente centinaia di varianti) e la mia opinione è che poiché gli utenti in genere hanno molte schede del browser aperte e ogni sito Web tende a succhiare molta CPU che Ho preferito questa implementazione per mantenere un'alta efficienza.
Skychan,

2

Ciò viola il principio DRY, ma è una soluzione concisa:

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>

Questo va bene per gli URI, ma per uso generale, avere una stringa contiene sia il formato che i componenti è molto fragile. Cosa succede se la stringa contiene virgole?
Michael Blackburn,

0

Non sono riuscito a ottenere la risposta di Josh Stodola al lavoro, ma quanto segue ha funzionato per me. Nota le specifiche di prototype. (Testato su IE, FF, Chrome e 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;
}

sin realtà dovrebbe essere un clone di thismodo da non essere un metodo distruttivo, ma non è davvero necessario.


Non è un metodo distruttivo. Quando s viene riassegnato con il valore restituito di s.replace (), questo rimane intatto.
gpvos,

0

Espandendo la grande risposta di adamJLev sopra , ecco la versione di TypeScript:

// 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

Ho un plunker che lo aggiunge al prototipo di stringa: string.format Non è solo breve come alcuni degli altri esempi, ma molto più flessibile.

L'utilizzo è simile alla versione c #:

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

Inoltre, è stato aggiunto il supporto per l'utilizzo di nomi e proprietà dell'oggetto

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

È inoltre possibile chiudere l'array con sostituzioni come questa.

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

o puoi provare bind

'/getElement/_/_/_'.replace(/_/g, (function(_) {return this.ar[this.i++];}).bind({ar: ["invoice", "id", 1337],i: 0}))
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.