Équivalent de String.format dans jQuery

194

J'essaie de déplacer du code JavaScript de MicrosoftAjax vers JQuery. J'utilise les équivalents JavaScript dans MicrosoftAjax des méthodes .net populaires, par exemple String.format (), String.startsWith (), etc. Y a-t-il des équivalents dans jQuery?

Waleed Eissa
la source

Réponses:

193

Le code source d'ASP.NET AJAX est disponible pour votre référence, vous pouvez donc le parcourir et inclure les pièces que vous souhaitez continuer à utiliser dans un fichier JS distinct. Ou, vous pouvez les porter sur jQuery.

Voici la fonction de formatage ...

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

Et voici les finsAvec et commenceAvec les fonctions prototypes ...

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);
}
Josh Stodola
la source
2
Il ne semble pas y avoir grand-chose. La version JavaScript n'a pas tous les trucs de mise en forme de nombres fantaisie, évidemment. blog.stevex.net/index.php/string-formatting-in-csharp
Nosredna
Wow, j'ai déjà pensé à cela, mais je pensais aussi que ce n'était pas possible à cause de la licence, je ne savais pas qu'ils l'avaient publiée sous licence permissive Microsoft, merci beaucoup pour cela
Waleed Eissa
23
Licence ou pas de licence .. il n'y a qu'une seule bonne façon d'écrire quelque chose d'aussi simple
adamJLev
1
La construction (puis la suppression) d'un objet RegEx pour chaque argument à chaque appel de format peut surcharger le garbage collector.
mckoss
14
Avertissement: Cela formera récursivement: donc si vous en avez {0}{1}, {0}sera remplacé en premier, puis toutes les occurrences de {1}dans le texte déjà substitué et le format d'origine seront remplacées.
Zenexer
147

Il s'agit d'une variante plus rapide / plus simple (et prototypique) de la fonction que Josh a publiée:

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

Usage:

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

Je l'utilise tellement que je l'ai aliasé juste f, mais vous pouvez également utiliser le plus verbeux format. par exemple'Hello {0}!'.format(name)

adamJLev
la source
1
Avec les navigateurs modernes, il existe des approches encore plus simples: stackoverflow.com/a/41052964/120296
david
3
@david Template string n'est pas du tout la même chose. Ils sont du sucre syntaxique pour la concaténation de chaînes, ce qui est bien, mais pas comme le formatage. Ils s'exécutent instantanément, par conséquent, les remplacements doivent être dans la portée au point de définition. Vous ne pouvez pas les stocker dans un fichier texte ou une base de données pour cette raison. En fait, la seule façon de les stocker n'importe où est de les mettre dans une fonction. Une fonction de chaîne formatée accepte les remplacements de position qui ne se soucient pas du nom de la variable.
krowe2
131

La plupart des fonctions ci-dessus (à l'exception de Julian Jelfs) contiennent l'erreur suivante:

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

Ou, pour les variantes qui comptent à rebours à partir de la fin de la liste d'arguments:

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

Voici une fonction correcte. C'est une variante prototypique du code de Julian Jelfs, que j'ai rendu un peu plus serré:

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

Et voici une version légèrement plus avancée de la même chose, qui vous permet d'échapper aux accolades en les doublant:

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

Cela fonctionne correctement:

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

Voici une autre bonne mise en œuvre par Blair Mitchelmore, avec un tas de fonctionnalités supplémentaires intéressantes: https://web.archive.org/web/20120315214858/http://blairmitchelmore.com/javascript/string.format

gpvos
la source
Et un autre, que je n'ai pas examiné de trop près, mais qui semble implémenter des formats tels que {0: + $ #, 0.00; - $ #, 0.00; 0}: masterdata.dyndns.org/r/string_format_for_javascript
gpvos
Ooh, et celui qui utilise le format d'interpolation Python: code.google.com/p/jquery-utils/wiki/…
gpvos
L'implémentation du format dont j'ai mentionné deux commentaires a été déplacée vers masterdata.se/r/string_format_for_javascript
gpvos
Remarque: la réponse d'ianj ailleurs sur cette page vous permet d'utiliser des paramètres nommés au lieu de paramètres numériques. Si vous changez sa méthode en une méthode qui utilise des prototypes, vous devrez changer le deuxième paramètre de la fonction slice.call de 1 à 0.
gpvos
48

Création d'une fonction de format qui prend une collection ou un tableau comme arguments

Usage:

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];
    });
};
ianj
la source
5
Sympa, tout ce qui manque est: String.prototype.format = function (col) {return format (this, col);}
Erik
10
je préfère ne pas étendre la chaîne
ianj
3
il y a une petite faute de frappe dans l'utilisation: la 2ème ligne devrait être: format ("je peux parler {0} depuis que j'étais {1}", 'javascript', 10);
Guillaume Gendre
Pourquoi ne pas préférer étendre la chaîne en utilisant String.prototype?
Kiquenet
36

Il existe une option (quelque peu) officielle: jQuery.validator.format .

Livré avec jQuery Validation Plugin 1.6 (au moins).
Assez semblable auString.Format trouvé dans .NET.

Modifier le lien cassé fixe.

rsenna
la source
13

Bien que ce ne soit pas exactement ce que le Q demandait, j'en ai construit un qui est similaire mais utilise des espaces réservés nommés au lieu de numérotés. Personnellement, je préfère avoir des arguments nommés et simplement envoyer un objet comme argument (plus verbeux, mais plus facile à maintenir).

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

Voici un exemple d'utilisation ...

alert("Hello {name}".format({ name: 'World' }));
Brian
la source
8

À l'aide d'un navigateur moderne, qui prend en charge EcmaScript 2015 (ES6), vous pouvez profiter des chaînes de modèles . Au lieu de mettre en forme, vous pouvez directement y injecter la valeur de la variable:

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

Notez que la chaîne de modèle doit être écrite à l'aide de tiques inversées (`).

David
la source
6

Aucune des réponses présentées jusqu'à présent n'a d'optimisation évidente de l'utilisation de l'enceinte pour initialiser une fois et stocker les expressions régulières, pour les utilisations suivantes.

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

De plus, aucun des exemples ne respecte l'implémentation de format () s'il en existe déjà un.


la source
2
rx2 est inutile, voir mon implémentation; vous avez (parenthèses) dans rx1, mais n'utilisez pas la valeur qu'ils transmettent à la fonction interne. De plus, je pense que c'est une optimisation évidente à faire dans le moteur Javascript . Êtes-vous sûr que les navigateurs modernes ne font pas déjà cette optimisation en arrière-plan? Perl l'a fait en 1990. Vous avez raison, il devrait y avoir un wrapper autour de la fonction pour vérifier si elle est déjà implémentée.
gpvos
1
De plus, le test sur (args [idx] === "") me semble superflu: il est déjà couvert par le premier test sur cette ligne, car non défini! == "".
gpvos
4

Voici la mienne:

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

Pas à l'épreuve des balles mais fonctionne si vous l'utilisez judicieusement.

Julian Jelfs
la source
4

Bien au-delà de la fin de la saison, mais je viens de regarder les réponses données et j'ai ma valeur de tuppence:

Usage:

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

Méthode:

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

Résultat:

"aalert" is not defined
3.14 3.14 a{2}bc foo
RickL
la source
3

Vous pouvez maintenant utiliser des modèles de littéraux :

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

Arek Kostrzeba
la source
3
J'étais enthousiasmé par les littéraux de modèle jusqu'à ce que je voie qu'ils ne fonctionnent que lorsque la chaîne est définie à côté des variables de remplacement. Pour moi, cela les rend pratiquement inutiles; pour une raison ou une autre, la plupart de mes chaînes sont définies séparément du code qui les remplit / les utilise.
Pierre
2

Voici ma version qui est capable d'échapper à «{» et de nettoyer ces espaces réservés non attribués.

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);
}
Feng
la source
2

La réponse suivante est probablement la plus efficace mais a la mise en garde de ne convenir qu'à 1 à 1 mappages d'arguments. Cela utilise le moyen le plus rapide de concaténer des chaînes (semblable à un constructeur de chaînes: tableau de chaînes jointes). Ceci est mon propre code. Mais il a probablement besoin d'un meilleur séparateur.

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

Utilisez-le comme:

alert(String.format("<a href='~'>~</a>", ["one", "two"]));
Skychan
la source
2
La réponse acceptée est la meilleure réponse. Je donne une réponse unique qui est utile dans les scénarios où vous voulez comprimer chaque bit d'efficacité possible (longues boucles) et vous avez un mappage 1: 1 des arguments. Plus efficace cuz replace () et le nouveau Regex () ainsi que l'exécution du regex utilisent certainement plus de cycles CPU que le split simple ().
Skychan
Pas besoin de -1. Non, ce n'est pas largement applicable, mais il a raison, ce serait un peu plus efficace. Maintenant, pour l'auteur, une question d'architecture: quel type d'application traiterait un si grand ensemble de données sur le client que ce type d'optimisation serait nécessaire?
Michael Blackburn
Bon point Michael Blackburn. La plupart des situations sont probablement bien. Dans mon cas, je faisais face à une bonne quantité de données (variations de produits au sein d'un groupe de produits, donc peut-être des centaines de variantes) et mon opinion est que, puisque les utilisateurs ont généralement de nombreux onglets de navigateur ouverts et que chaque site Web a tendance à aspirer beaucoup de CPU qui J'ai préféré cette implémentation pour maintenir une efficacité élevée.
Skychan
2

Cela viole le principe DRY, mais c'est une solution concise:

var button = '<a href="{link}" class="btn">{text}</a>';
button = button.replace('{text}','Authorize on GitHub').replace('{link}', authorizeUrl);
ilyaigpetrov
la source
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>
Kishor Dalwadi
la source
C'est bien pour les URI, mais pour une utilisation générale, avoir une chaîne contenant à la fois le format et les composants est très fragile. Et si votre chaîne contient des virgules?
Michael Blackburn
0

Je n'ai pas pu obtenir la réponse de Josh Stodola au travail, mais ce qui suit a fonctionné pour moi. Notez la spécification de prototype. (Testé sur IE, FF, Chrome et 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;
}

sdevrait vraiment être un clone de thisne pas être une méthode destructrice, mais ce n'est pas vraiment nécessaire.

JellicleCat
la source
Ce n'est pas une méthode destructrice. Lorsque s est réaffecté avec la valeur de retour de s.replace (), cela reste inchangé.
gpvos
0

Développant la grande réponse d'adamJLev ci - dessus , voici la version 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;
};
Annie
la source
0

J'ai un plongeur qui l'ajoute au prototype de chaîne: string.format Il n'est pas seulement aussi court que certains des autres exemples, mais beaucoup plus flexible.

L'utilisation est similaire à la version 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

En outre, prise en charge supplémentaire de l'utilisation des noms et des propriétés des objets

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
ShrapNull
la source
0

Vous pouvez également fermer le tableau avec des remplacements comme celui-ci.

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

ou vous pouvez essayer bind

'/getElement/_/_/_'.replace(/_/g, (function(_) {return this.ar[this.i++];}).bind({ar: ["invoice", "id", 1337],i: 0}))
test30
la source