web-dev-qa-db-fra.com

Équivalent JavaScript de printf / String.Format

Je cherche un bon équivalent JavaScript de C/PHP printf() ou des programmeurs C #/Java, String.Format() (IFormatProvider pour .NET).

Mon exigence de base est un format de séparateur de milliers pour les chiffres pour le moment, mais quelque chose qui gère beaucoup de combinaisons (y compris les dates) serait bien.

Je me rends compte que la bibliothèque Ajax de Microsoft fournit une version de String.Format(), mais nous ne voulons pas de la surcharge totale de ce framework.

1828
Chris S

À partir de ES6, vous pouvez utiliser des chaînes de modèle:

let soMany = 10;
console.log(`This is ${soMany} times easier!`);
// "This is 10 times easier!

Voir Kim's réponse ci-dessous pour plus de détails.


Autrement:

Essayez sprintf () pour JavaScript .


Si vous voulez vraiment faire vous-même une méthode de formatage simple, ne faites pas les remplacements successivement, mais faites-les simultanément.

Parce que la plupart des autres propositions mentionnées échouent lorsqu'une chaîne de remplacement d'un remplacement précédent contient également une séquence de format similaire à celle-ci:

"{0}{1}".format("{1}", "{0}")

Normalement, vous vous attendez à ce que la sortie soit {1}{0} mais la sortie réelle est {1}{1}. Par conséquent, effectuez un remplacement simultané, comme dans suggestion de fearphage .

946
Gumbo

Construire sur les solutions proposées précédemment:

// First, checks if it isn't implemented yet.
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} is dead, but {1} is alive! {0} {2}".format("ASP", "ASP.NET")

les sorties

ASP est mort, mais ASP.NET est vivant! ASP {2}


Si vous préférez ne pas modifier le prototype de String:

if (!String.format) {
  String.format = function(format) {
    var args = Array.prototype.slice.call(arguments, 1);
    return format.replace(/{(\d+)}/g, function(match, number) { 
      return typeof args[number] != 'undefined'
        ? args[number] 
        : match
      ;
    });
  };
}

Vous donne le beaucoup plus familier:

String.format('{0} is dead, but {1} is alive! {0} {2}', 'ASP', 'ASP.NET');

avec le même résultat:

ASP est mort, mais ASP.NET est vivant! ASP {2}

1351
fearphage

C'est amusant parce que Stack Overflow possède sa propre fonction de formatage pour le prototype String appelé formatUnicorn. Essayez le! Allez dans la console et tapez quelque chose comme:

_"Hello, {name}, are you feeling {adjective}?".formatUnicorn({name:"Gabriel", adjective: "OK"});
_

Firebug

Vous obtenez cette sortie:

_Hello, Gabriel, are you feeling OK?_

Vous pouvez utiliser des objets, des tableaux et des chaînes comme arguments! J'ai eu son code et l'ai retravaillé pour produire une nouvelle version de _String.prototype.format_:

_String.prototype.formatUnicorn = String.prototype.formatUnicorn ||
function () {
    "use strict";
    var str = this.toString();
    if (arguments.length) {
        var t = typeof arguments[0];
        var key;
        var args = ("string" === t || "number" === t) ?
            Array.prototype.slice.call(arguments)
            : arguments[0];

        for (key in args) {
            str = str.replace(new RegExp("\\{" + key + "\\}", "gi"), args[key]);
        }
    }

    return str;
};
_

Notez l'appel astucieux Array.prototype.slice.call(arguments) - cela signifie que si vous ajoutez des arguments sous forme de chaînes ou de chiffres, et non un seul objet de style JSON, vous obtenez le comportement de C # String.Format presque exactement .

_"a{0}bcd{1}ef".formatUnicorn("foo", "bar"); // yields "aFOObcdBARef"
_

C'est parce que Array de slice va forcer tout ce qui se trouve dans arguments dans un Array, que ce soit à l'origine ou non, et le key sera l'index (0, 1, 2 ...) de chaque élément de tableau contraint dans une chaîne (par exemple, "0", donc _"\\{0\\}"_ pour votre premier motif d'expression rationnelle).

Soigné.

435
Gabriel Nahmias

Mise en forme des nombres en JavaScript

Je suis arrivé à cette page de question dans l'espoir de trouver comment formater des nombres en JavaScript, sans introduire une autre bibliothèque. Voici ce que j'ai trouvé:

Arrondir des nombres à virgule flottante

L'équivalent de sprintf("%.2f", num) dans JavaScript semble être num.toFixed(2), qui formate num avec 2 décimales, avec arrondi (voir le commentaire de @ ars265 sur Math.round ci-dessous).

(12.345).toFixed(2); // returns "12.35" (rounding!)
(12.3).toFixed(2); // returns "12.30" (zero padding)

Forme exponentielle

L'équivalent de sprintf("%.2e", num) est num.toExponential(2).

(33333).toExponential(2); // "3.33e+4"

Base hexadécimale et autres

Pour imprimer des nombres en base B, essayez num.toString(B). JavaScript prend en charge la conversion automatique vers et à partir des bases 2 à 36 (certains navigateurs ont en outre prise en charge limitée du codage base64 ).

(3735928559).toString(16); // to base 16: "deadbeef"
parseInt("deadbeef", 16); // from base 16: 3735928559

Pages de référence

Petit tutoriel sur le formatage des nombres JS

page de référence de Mozilla pour toFixed () (avec des liens vers toPrecision (), toExponential (), toLocaleString (), ...)

307
rescdsk

A partir de ES6, vous pouvez utiliser des chaînes de modèle :

let soMany = 10;
console.log(`This is ${soMany} times easier!`);
// "This is 10 times easier!

Sachez que les chaînes de modèles sont entourées de guillemets `au lieu de guillemets (simples).

Pour plus d'informations:

https://developers.google.com/web/updates/2015/01/ES6-Template-Strings

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/template_strings

Remarque: Consultez le site mozilla pour trouver la liste des navigateurs pris en charge.

219
Kim

jsxt, Zippo

Cette option convient mieux.

String.prototype.format = function() {
    var formatted = this;
    for (var i = 0; i < arguments.length; i++) {
        var regexp = new RegExp('\\{'+i+'\\}', 'gi');
        formatted = formatted.replace(regexp, arguments[i]);
    }
    return formatted;
};

Avec cette option, je peux remplacer des chaînes comme celles-ci:

'The {0} is dead. Don\'t code {0}. Code {1} that is open source!'.format('ASP', 'PHP');

Avec votre code, le second {0} ne sera pas remplacé. ;)

170
Filipiz

J'utilise cette fonction simple:

String.prototype.format = function() {
    var formatted = this;
    for( var arg in arguments ) {
        formatted = formatted.replace("{" + arg + "}", arguments[arg]);
    }
    return formatted;
};

C'est très similaire à string.format:

"{0} is dead, but {1} is alive!".format("ASP", "ASP.NET")
105
Moshe Revah

Pour Node.js utilisateurs, il y a util.format qui a une fonctionnalité analogue à celle de printf:

_util.format("%s world", "Hello")
_
60
George Eracleous

Voici une minimale implémentation de sprintf en JavaScript: elle ne fait que "% s" et "% d", mais j'ai laissé de la place pour son extension. Cela ne sert à rien pour le PO, mais d’autres personnes qui tombent sur ce fil venant de Google pourraient en tirer profit.

function sprintf() {
    var args = arguments,
    string = args[0],
    i = 1;
    return string.replace(/%((%)|s|d)/g, function (m) {
        // m is the matched format, e.g. %s, %d
        var val = null;
        if (m[2]) {
            val = m[2];
        } else {
            val = args[i];
            // A switch statement so that the formatter can be extended. Default is %s
            switch (m) {
                case '%d':
                    val = parseFloat(val);
                    if (isNaN(val)) {
                        val = 0;
                    }
                    break;
            }
            i++;
        }
        return val;
    });
}

Exemple:

alert(sprintf('Latitude: %s, Longitude: %s, Count: %d', 41.847, -87.661, 'two'));
// Expected output: Latitude: 41.847, Longitude: -87.661, Count: 0

Contrairement aux solutions similaires des réponses précédentes, celle-ci effectue toutes les substitutions en une fois, de sorte qu'elle ne remplacera pas des parties des valeurs précédemment remplacées.

51
bart

Je suis surpris que personne ne l'utilise reduce , il s'agit d'une fonction JavaScript native concise et puissante.

ES6 (EcmaScript2015)

String.prototype.format = function() {
  return [...arguments].reduce((p,c) => p.replace(/%s/,c), this);
};

console.log('Is that a %s or a %s?... No, it\'s %s!'.format('plane', 'bird', 'SOman'));

<ES6

function interpolate(theString, argumentArray) {
    var regex = /%s/;
    var _r=function(p,c){return p.replace(regex,c);}
    return argumentArray.reduce(_r, theString);
}

interpolate("%s, %s and %s", ["Me", "myself", "I"]); // "Me, myself and I"

Comment ça fonctionne:

reduction applique une fonction à un accumulateur et à chaque élément du tableau (de gauche à droite) pour le réduire à une valeur unique.

var _r= function(p,c){return p.replace(/%s/,c)};

console.log(
  ["a", "b", "c"].reduce(_r, "[%s], [%s] and [%s]") + '\n',
  [1, 2, 3].reduce(_r, "%s+%s=%s") + '\n',
  ["cool", 1337, "stuff"].reduce(_r, "%s %s %s")
);
50
Monarch Wadia

Les programmeurs JavaScript peuvent utiliser String.prototype.sprintf à l'adresse https://github.com/ildar-shaimordanov/jsxt/blob/master/js/String.js . Voici un exemple:

var d = new Date();
var dateStr = '%02d:%02d:%02d'.sprintf(
    d.getHours(), 
    d.getMinutes(), 
    d.getSeconds());
31
jsxt

Ajoutant à la réponse de zippoxer, j'utilise cette fonction:

String.prototype.format = function () {
    var a = this, b;
    for (b in arguments) {
        a = a.replace(/%[a-z]/, arguments[b]);
    }
    return a; // Make chainable
};

var s = 'Hello %s The magic number is %d.';
s.format('world!', 12); // Hello World! The magic number is 12.

J'ai également une version non-prototype que j'utilise plus souvent pour sa syntaxe semblable à Java:

function format() {
    var a, b, c;
    a = arguments[0];
    b = [];
    for(c = 1; c < arguments.length; c++){
        b.Push(arguments[c]);
    }
    for (c in b) {
        a = a.replace(/%[a-z]/, b[c]);
    }
    return a;
}
format('%d ducks, 55 %s', 12, 'cats'); // 12 ducks, 55 cats

Mise à jour ES 2015

Toutes les nouvelles fonctionnalités d'ES 2015 facilitent grandement la tâche:

function format(fmt, ...args){
    return fmt
        .split("%%")
        .reduce((aggregate, chunk, i) =>
            aggregate + chunk + (args[i] || ""), "");
}

format("Hello %%! I ate %% apples today.", "World", 44);
// "Hello World, I ate 44 apples today."

Je me suis dit que puisque ceci, comme les plus anciens, n'analyse pas réellement les lettres, il pourrait tout aussi bien utiliser un seul jeton %%. Cela présente l’avantage d’être évident et de ne pas rendre difficile l’utilisation d’un seul %. Cependant, si vous avez besoin de %% pour une raison quelconque, vous devrez le remplacer par lui-même:

format("I love percentage signs! %%", "%%");
// "I love percentage signs! %%"
21
Braden Best

+1 Zippo avec l'exception que le corps de la fonction doit être comme ci-dessous ou sinon il ajoute la chaîne en cours à chaque itération:

String.prototype.format = function() {
    var formatted = this;
    for (var arg in arguments) {
        formatted = formatted.replace("{" + arg + "}", arguments[arg]);
    }
    return formatted;
};
21
user437231

J'ajouterai mes propres découvertes que j'ai découvertes depuis que j'ai demandé:

Malheureusement, il semble que sprintf ne gère pas le formatage des séparateurs de milliers, comme le format de chaîne de .NET.

15
Chris S

Très élégant:

String.prototype.format = function (){
    var args = arguments;
    return this.replace(/\{\{|\}\}|\{(\d+)\}/g, function (curlyBrack, index) {
        return ((curlyBrack == "{{") ? "{" : ((curlyBrack == "}}") ? "}" : args[index]));
    });
};

// Usage:
"{0}{1}".format("{1}", "{0}")

Le crédit va à (lien brisé) https://Gist.github.com/0i0/1519811

14
lior hakim

J'utilise une petite bibliothèque appelée String.format pour JavaScript , qui prend en charge la plupart des fonctionnalités de formatage de chaîne (y compris le format des nombres et des dates) et utilise la syntaxe .NET. Le script lui-même est inférieur à 4 Ko, il ne génère donc pas beaucoup de temps système.

14
Sven N

Je veux partager ma solution pour le "problème". Je n'ai pas réinventé la roue, mais j'essaie de trouver une solution basée sur ce que JavaScript fait déjà. L'avantage est que vous obtenez toutes les conversions implicites gratuitement. La définition de la propriété prototype $ of String donne une syntaxe très agréable et compacte (voir les exemples ci-dessous). Ce n'est peut-être pas le moyen le plus efficace, mais dans la plupart des cas, le rendement ne doit pas être optimisé.

String.form = function(str, arr) {
    var i = -1;
    function callback(exp, p0, p1, p2, p3, p4) {
        if (exp=='%%') return '%';
        if (arr[++i]===undefined) return undefined;
        exp  = p2 ? parseInt(p2.substr(1)) : undefined;
        var base = p3 ? parseInt(p3.substr(1)) : undefined;
        var val;
        switch (p4) {
            case 's': val = arr[i]; break;
            case 'c': val = arr[i][0]; break;
            case 'f': val = parseFloat(arr[i]).toFixed(exp); break;
            case 'p': val = parseFloat(arr[i]).toPrecision(exp); break;
            case 'e': val = parseFloat(arr[i]).toExponential(exp); break;
            case 'x': val = parseInt(arr[i]).toString(base?base:16); break;
            case 'd': val = parseFloat(parseInt(arr[i], base?base:10).toPrecision(exp)).toFixed(0); break;
        }
        val = typeof(val)=='object' ? JSON.stringify(val) : val.toString(base);
        var sz = parseInt(p1); /* padding size */
        var ch = p1 && p1[0]=='0' ? '0' : ' '; /* isnull? */
        while (val.length<sz) val = p0 !== undefined ? val+ch : ch+val; /* isminus? */
       return val;
    }
    var regex = /%(-)?(0?[0-9]+)?([.][0-9]+)?([#][0-9]+)?([scfpexd%])/g;
    return str.replace(regex, callback);
}

String.prototype.$ = function() {
    return String.form(this, Array.prototype.slice.call(arguments));
}

Voici quelques exemples:

String.format("%s %s", [ "This is a string", 11 ])
console.log("%s %s".$("This is a string", 11))
var arr = [ "12.3", 13.6 ]; console.log("Array: %s".$(arr));
var obj = { test:"test", id:12 }; console.log("Object: %s".$(obj));
console.log("%c", "Test");
console.log("%5d".$(12)); // '   12'
console.log("%05d".$(12)); // '00012'
console.log("%-5d".$(12)); // '12   '
console.log("%5.2d".$(123)); // '  120'
console.log("%5.2f".$(1.1)); // ' 1.10'
console.log("%10.2e".$(1.1)); // '   1.10e+0'
console.log("%5.3p".$(1.12345)); // ' 1.12'
console.log("%5x".$(45054)); // ' affe'
console.log("%20#2x".$("45054")); // '    1010111111111110'
console.log("%6#2d".$("111")); // '     7'
console.log("%6#16d".$("affe")); // ' 45054'
14
Rtlprmft

Si vous souhaitez gérer le séparateur de milliers, vous devriez vraiment utiliser toLocaleString () à partir de la classe JavaScript Number car elle formatera la chaîne pour la région de l'utilisateur.

La classe JavaScript Date peut formater les dates et heures localisées.

11
17 of 26

J'ai une solution très proche de celle de Peter, mais elle traite du nombre et de la cause de l'objet.

if (!String.prototype.format) {
  String.prototype.format = function() {
    var args;
    args = arguments;
    if (args.length === 1 && args[0] !== null && typeof args[0] === 'object') {
      args = args[0];
    }
    return this.replace(/{([^}]*)}/g, function(match, key) {
      return (typeof args[key] !== "undefined" ? args[key] : match);
    });
  };
}

Peut-être serait-il encore mieux de traiter les cas graves, mais pour mes besoins, c'est très bien.

"This is an example from {name}".format({name:"Blaine"});
"This is an example from {0}".format("Blaine");

PS: Cette fonction est très pratique si vous utilisez des traductions dans des frameworks de templates tels que AngularJS :

<h1> {{('hello-message'|translate).format(user)}} <h1>
<h1> {{('hello-by-name'|translate).format( user ? user.name : 'You' )}} <h1>

Où le en.json est quelque chose comme

{
    "hello-message": "Hello {name}, welcome.",
    "hello-by-name": "Hello {0}, welcome."
}
9
Thiago Mata

J'utilise celui-ci:

String.prototype.format = function() {
    var newStr = this, i = 0;
    while (/%s/.test(newStr))
        newStr = newStr.replace("%s", arguments[i++])

    return newStr;
}

Alors je l'appelle:

"<h1>%s</h1><p>%s</p>".format("Header", "Just a test!");
8
redestructa

Le projet PHPJS a écrit des implémentations JavaScript pour de nombreuses fonctions de PHP. Puisque la fonction sprintf() de PHP est fondamentalement identique à celle de printf(), de C, leur implémentation JavaScript devrait répondre à vos besoins.

8
Spudley

Une version très légèrement différente, celle que je préfère (celle-ci utilise {xxx} jetons au lieu de {0} arguments numérotés, elle est beaucoup plus documentée et convient mieux à la localisation):

String.prototype.format = function(tokens) {
  var formatted = this;
  for (var token in tokens)
    if (tokens.hasOwnProperty(token))
      formatted = formatted.replace(RegExp("{" + token + "}", "g"), tokens[token]);
  return formatted;
};

Une variation serait:

  var formatted = l(this);

qui appelle une fonction de localisation l() en premier.

7
Peter

Pour ceux qui aiment Node.JS et sa fonctionnalité util.format , je viens de l'extraire dans sa forme JavaScript Vanilla (avec uniquement les fonctions util.format les usages):

_exports = {};

function isString(arg) {
    return typeof arg === 'string';
}
function isNull(arg) {
    return arg === null;
}
function isObject(arg) {
    return typeof arg === 'object' && arg !== null;
}
function isBoolean(arg) {
    return typeof arg === 'boolean';
}
function isUndefined(arg) {
    return arg === void 0;
}
function stylizeNoColor(str, styleType) {
    return str;
}
function stylizeWithColor(str, styleType) {
    var style = inspect.styles[styleType];

    if (style) {
        return '\u001b[' + inspect.colors[style][0] + 'm' + str +
            '\u001b[' + inspect.colors[style][3] + 'm';
    } else {
        return str;
    }
}
function isFunction(arg) {
    return typeof arg === 'function';
}
function isNumber(arg) {
    return typeof arg === 'number';
}
function isSymbol(arg) {
    return typeof arg === 'symbol';
}
function formatPrimitive(ctx, value) {
    if (isUndefined(value))
        return ctx.stylize('undefined', 'undefined');
    if (isString(value)) {
        var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
                .replace(/'/g, "\\'")
                .replace(/\\"/g, '"') + '\'';
        return ctx.stylize(simple, 'string');
    }
    if (isNumber(value)) {
        // Format -0 as '-0'. Strict equality won't distinguish 0 from -0,
        // so instead we use the fact that 1 / -0 < 0 whereas 1 / 0 > 0 .
        if (value === 0 && 1 / value < 0)
            return ctx.stylize('-0', 'number');
        return ctx.stylize('' + value, 'number');
    }
    if (isBoolean(value))
        return ctx.stylize('' + value, 'boolean');
    // For some reason typeof null is "object", so special case here.
    if (isNull(value))
        return ctx.stylize('null', 'null');
    // es6 symbol primitive
    if (isSymbol(value))
        return ctx.stylize(value.toString(), 'symbol');
}
function arrayToHash(array) {
    var hash = {};

    array.forEach(function (val, idx) {
        hash[val] = true;
    });

    return hash;
}
function objectToString(o) {
    return Object.prototype.toString.call(o);
}
function isDate(d) {
    return isObject(d) && objectToString(d) === '[object Date]';
}
function isError(e) {
    return isObject(e) &&
        (objectToString(e) === '[object Error]' || e instanceof Error);
}
function isRegExp(re) {
    return isObject(re) && objectToString(re) === '[object RegExp]';
}
function formatError(value) {
    return '[' + Error.prototype.toString.call(value) + ']';
}
function formatPrimitiveNoColor(ctx, value) {
    var stylize = ctx.stylize;
    ctx.stylize = stylizeNoColor;
    var str = formatPrimitive(ctx, value);
    ctx.stylize = stylize;
    return str;
}
function isArray(ar) {
    return Array.isArray(ar);
}
function hasOwnProperty(obj, prop) {
    return Object.prototype.hasOwnProperty.call(obj, prop);
}
function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
    var name, str, desc;
    desc = Object.getOwnPropertyDescriptor(value, key) || {value: value[key]};
    if (desc.get) {
        if (desc.set) {
            str = ctx.stylize('[Getter/Setter]', 'special');
        } else {
            str = ctx.stylize('[Getter]', 'special');
        }
    } else {
        if (desc.set) {
            str = ctx.stylize('[Setter]', 'special');
        }
    }
    if (!hasOwnProperty(visibleKeys, key)) {
        name = '[' + key + ']';
    }
    if (!str) {
        if (ctx.seen.indexOf(desc.value) < 0) {
            if (isNull(recurseTimes)) {
                str = formatValue(ctx, desc.value, null);
            } else {
                str = formatValue(ctx, desc.value, recurseTimes - 1);
            }
            if (str.indexOf('\n') > -1) {
                if (array) {
                    str = str.split('\n').map(function (line) {
                        return '  ' + line;
                    }).join('\n').substr(2);
                } else {
                    str = '\n' + str.split('\n').map(function (line) {
                        return '   ' + line;
                    }).join('\n');
                }
            }
        } else {
            str = ctx.stylize('[Circular]', 'special');
        }
    }
    if (isUndefined(name)) {
        if (array && key.match(/^\d+$/)) {
            return str;
        }
        name = JSON.stringify('' + key);
        if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
            name = name.substr(1, name.length - 2);
            name = ctx.stylize(name, 'name');
        } else {
            name = name.replace(/'/g, "\\'")
                .replace(/\\"/g, '"')
                .replace(/(^"|"$)/g, "'")
                .replace(/\\\\/g, '\\');
            name = ctx.stylize(name, 'string');
        }
    }

    return name + ': ' + str;
}
function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {
    var output = [];
    for (var i = 0, l = value.length; i < l; ++i) {
        if (hasOwnProperty(value, String(i))) {
            output.Push(formatProperty(ctx, value, recurseTimes, visibleKeys,
                String(i), true));
        } else {
            output.Push('');
        }
    }
    keys.forEach(function (key) {
        if (!key.match(/^\d+$/)) {
            output.Push(formatProperty(ctx, value, recurseTimes, visibleKeys,
                key, true));
        }
    });
    return output;
}
function reduceToSingleString(output, base, braces) {
    var length = output.reduce(function (prev, cur) {
        return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1;
    }, 0);

    if (length > 60) {
        return braces[0] +
            (base === '' ? '' : base + '\n ') +
            ' ' +
            output.join(',\n  ') +
            ' ' +
            braces[1];
    }

    return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
}
function formatValue(ctx, value, recurseTimes) {
    // Provide a hook for user-specified inspect functions.
    // Check that value is an object with an inspect function on it
    if (ctx.customInspect &&
        value &&
        isFunction(value.inspect) &&
            // Filter out the util module, it's inspect function is special
        value.inspect !== exports.inspect &&
            // Also filter out any prototype objects using the circular check.
        !(value.constructor && value.constructor.prototype === value)) {
        var ret = value.inspect(recurseTimes, ctx);
        if (!isString(ret)) {
            ret = formatValue(ctx, ret, recurseTimes);
        }
        return ret;
    }

    // Primitive types cannot have properties
    var primitive = formatPrimitive(ctx, value);
    if (primitive) {
        return primitive;
    }

    // Look up the keys of the object.
    var keys = Object.keys(value);
    var visibleKeys = arrayToHash(keys);

    if (ctx.showHidden) {
        keys = Object.getOwnPropertyNames(value);
    }

    // This could be a boxed primitive (new String(), etc.), check valueOf()
    // NOTE: Avoid calling `valueOf` on `Date` instance because it will return
    // a number which, when object has some additional user-stored `keys`,
    // will be printed out.
    var formatted;
    var raw = value;
    try {
        // the .valueOf() call can fail for a multitude of reasons
        if (!isDate(value))
            raw = value.valueOf();
    } catch (e) {
        // ignore...
    }

    if (isString(raw)) {
        // for boxed Strings, we have to remove the 0-n indexed entries,
        // since they just noisey up the output and are redundant
        keys = keys.filter(function (key) {
            return !(key >= 0 && key < raw.length);
        });
    }

    // Some type of object without properties can be shortcutted.
    if (keys.length === 0) {
        if (isFunction(value)) {
            var name = value.name ? ': ' + value.name : '';
            return ctx.stylize('[Function' + name + ']', 'special');
        }
        if (isRegExp(value)) {
            return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
        }
        if (isDate(value)) {
            return ctx.stylize(Date.prototype.toString.call(value), 'date');
        }
        if (isError(value)) {
            return formatError(value);
        }
        // now check the `raw` value to handle boxed primitives
        if (isString(raw)) {
            formatted = formatPrimitiveNoColor(ctx, raw);
            return ctx.stylize('[String: ' + formatted + ']', 'string');
        }
        if (isNumber(raw)) {
            formatted = formatPrimitiveNoColor(ctx, raw);
            return ctx.stylize('[Number: ' + formatted + ']', 'number');
        }
        if (isBoolean(raw)) {
            formatted = formatPrimitiveNoColor(ctx, raw);
            return ctx.stylize('[Boolean: ' + formatted + ']', 'boolean');
        }
    }

    var base = '', array = false, braces = ['{', '}'];

    // Make Array say that they are Array
    if (isArray(value)) {
        array = true;
        braces = ['[', ']'];
    }

    // Make functions say that they are functions
    if (isFunction(value)) {
        var n = value.name ? ': ' + value.name : '';
        base = ' [Function' + n + ']';
    }

    // Make RegExps say that they are RegExps
    if (isRegExp(value)) {
        base = ' ' + RegExp.prototype.toString.call(value);
    }

    // Make dates with properties first say the date
    if (isDate(value)) {
        base = ' ' + Date.prototype.toUTCString.call(value);
    }

    // Make error with message first say the error
    if (isError(value)) {
        base = ' ' + formatError(value);
    }

    // Make boxed primitive Strings look like such
    if (isString(raw)) {
        formatted = formatPrimitiveNoColor(ctx, raw);
        base = ' ' + '[String: ' + formatted + ']';
    }

    // Make boxed primitive Numbers look like such
    if (isNumber(raw)) {
        formatted = formatPrimitiveNoColor(ctx, raw);
        base = ' ' + '[Number: ' + formatted + ']';
    }

    // Make boxed primitive Booleans look like such
    if (isBoolean(raw)) {
        formatted = formatPrimitiveNoColor(ctx, raw);
        base = ' ' + '[Boolean: ' + formatted + ']';
    }

    if (keys.length === 0 && (!array || value.length === 0)) {
        return braces[0] + base + braces[1];
    }

    if (recurseTimes < 0) {
        if (isRegExp(value)) {
            return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
        } else {
            return ctx.stylize('[Object]', 'special');
        }
    }

    ctx.seen.Push(value);

    var output;
    if (array) {
        output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);
    } else {
        output = keys.map(function (key) {
            return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);
        });
    }

    ctx.seen.pop();

    return reduceToSingleString(output, base, braces);
}
function inspect(obj, opts) {
    // default options
    var ctx = {
        seen: [],
        stylize: stylizeNoColor
    };
    // legacy...
    if (arguments.length >= 3) ctx.depth = arguments[2];
    if (arguments.length >= 4) ctx.colors = arguments[3];
    if (isBoolean(opts)) {
        // legacy...
        ctx.showHidden = opts;
    } else if (opts) {
        // got an "options" object
        exports._extend(ctx, opts);
    }
    // set default options
    if (isUndefined(ctx.showHidden)) ctx.showHidden = false;
    if (isUndefined(ctx.depth)) ctx.depth = 2;
    if (isUndefined(ctx.colors)) ctx.colors = false;
    if (isUndefined(ctx.customInspect)) ctx.customInspect = true;
    if (ctx.colors) ctx.stylize = stylizeWithColor;
    return formatValue(ctx, obj, ctx.depth);
}
exports.inspect = inspect;


// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
inspect.colors = {
    'bold': [1, 22],
    'italic': [3, 23],
    'underline': [4, 24],
    'inverse': [7, 27],
    'white': [37, 39],
    'grey': [90, 39],
    'black': [30, 39],
    'blue': [34, 39],
    'cyan': [36, 39],
    'green': [32, 39],
    'Magenta': [35, 39],
    'red': [31, 39],
    'yellow': [33, 39]
};

// Don't use 'blue' not visible on cmd.exe
inspect.styles = {
    'special': 'cyan',
    'number': 'yellow',
    'boolean': 'yellow',
    'undefined': 'grey',
    'null': 'bold',
    'string': 'green',
    'symbol': 'green',
    'date': 'Magenta',
    // "name": intentionally not styling
    'regexp': 'red'
};


var formatRegExp = /%[sdj%]/g;
exports.format = function (f) {
    if (!isString(f)) {
        var objects = [];
        for (var j = 0; j < arguments.length; j++) {
            objects.Push(inspect(arguments[j]));
        }
        return objects.join(' ');
    }

    var i = 1;
    var args = arguments;
    var len = args.length;
    var str = String(f).replace(formatRegExp, function (x) {
        if (x === '%%') return '%';
        if (i >= len) return x;
        switch (x) {
            case '%s':
                return String(args[i++]);
            case '%d':
                return Number(args[i++]);
            case '%j':
                try {
                    return JSON.stringify(args[i++]);
                } catch (_) {
                    return '[Circular]';
                }
            default:
                return x;
        }
    });
    for (var x = args[i]; i < len; x = args[++i]) {
        if (isNull(x) || !isObject(x)) {
            str += ' ' + x;
        } else {
            str += ' ' + inspect(x);
        }
    }
    return str;
};
_

Récolté depuis: https://github.com/joyent/node/blob/master/lib/util.js

6
A T

Il existe "sprintf" pour JavaScript que vous pouvez trouver sur http://www.webtoolkit.info/javascript-sprintf.html .

6
Pooria

Juste au cas où quelqu'un aurait besoin d'une fonction anti-pollution globale, voici la fonction qui fait la même chose:

  function _format (str, arr) {
    return str.replace(/{(\d+)}/g, function (match, number) {
      return typeof arr[number] != 'undefined' ? arr[number] : match;
    });
  };
5
Afshin Mehrabani

Pour le formatage de base:

var template = jQuery.validator.format("{0} is not a valid value");
var result = template("abc");
5
Evgeny Gerbut

J'ai un formateur légèrement plus long pour JavaScript ici ...

Vous pouvez effectuer le formatage de plusieurs manières:

  • String.format(input, args0, arg1, ...)
  • String.format(input, obj)
  • "literal".format(arg0, arg1, ...)
  • "literal".format(obj)

De même, si vous avez déclaré un ObjectBase.prototype.format (tel que DateJS ), il l'utilisera.

Exemples...

var input = "numbered args ({0}-{1}-{2}-{3})";
console.log(String.format(input, "first", 2, new Date()));
//Outputs "numbered args (first-2-Thu May 31 2012...Time)-{3})"

console.log(input.format("first", 2, new Date()));
//Outputs "numbered args(first-2-Thu May 31 2012...Time)-{3})"

console.log(input.format(
    "object properties ({first}-{second}-{third:yyyy-MM-dd}-{fourth})"
    ,{
        'first':'first'
        ,'second':2
        ,'third':new Date() //assumes Date.prototype.format method
    }
));
//Outputs "object properties (first-2-2012-05-31-{3})"

J'ai également créé un alias avec .asFormat et une certaine détection est en place au cas où il existe déjà un string.format (comme avec MS Ajax Toolkit (je déteste cette bibliothèque).

5
Tracker1

En utilisant Lodash , vous pouvez obtenir la fonctionnalité de modèle:

Utilisez le délimiteur de littéral de modèle ES en tant que délimiteur "interpoler". Désactivez la prise en charge en remplaçant le délimiteur "interpoler".

var compiled = _.template('hello ${ user }!');
compiled({ 'user': 'pebbles' });
// => 'hello pebbles!
2
Yevgeniy Afanasyev

À utiliser avec les fonctions de réussite jQuery.ajax (). Ne passez qu'un seul argument et remplacez la chaîne par les propriétés de cet objet sous la forme {propertyName}:

String.prototype.format = function () {
    var formatted = this;
    for (var prop in arguments[0]) {
        var regexp = new RegExp('\\{' + prop + '\\}', 'gi');
        formatted = formatted.replace(regexp, arguments[0][prop]);
    }
    return formatted;
};

Exemple:

var userInfo = ("Email: {Email} - Phone: {Phone}").format({ Email: "[email protected]", Phone: "123-123-1234" });
2
Raymond Powell

Je n'ai pas vu pyformat dans la liste et j'ai donc pensé l'inclure:

console.log(pyformat( 'The {} {} jumped over the {}'
                , ['brown' ,'fox' ,'foobar']
                ))
console.log(pyformat('The {0} {1} jumped over the {1}'
                , ['brown' ,'fox' ,'foobar']
                ))
console.log(pyformat('The {color} {animal} jumped over the {thing}'
                , [] ,{color: 'brown' ,animal: 'fox' ,thing: 'foobaz'}
                ))
2
Bovard
/**
 * Format string by replacing placeholders with value from element with
 * corresponsing index in `replacementArray`.
 * Replaces are made simultaneously, so that replacement values like
 * '{1}' will not mess up the function.
 *
 * Example 1:
 * ('{2} {1} {0}', ['three', 'two' ,'one']) -> 'one two three'
 *
 * Example 2:
 * ('{0}{1}', ['{1}', '{0}']) -> '{1}{0}'
 */
function stringFormat(formatString, replacementArray) {
    return formatString.replace(
        /\{(\d+)\}/g, // Matches placeholders, e.g. '{1}'
        function formatStringReplacer(match, placeholderIndex) {
            // Convert String to Number
            placeholderIndex = Number(placeholderIndex);

            // Make sure that index is within replacement array bounds
            if (placeholderIndex < 0 ||
                placeholderIndex > replacementArray.length - 1
            ) {
                return placeholderIndex;
            }

            // Replace placeholder with value from replacement array
            return replacementArray[placeholderIndex];
        }
    );
}

Je n'ai pas vu la variante String.format:

String.format = function (string) {
    var args = Array.prototype.slice.call(arguments, 1, arguments.length);
    return string.replace(/{(\d+)}/g, function (match, number) {
        return typeof args[number] != "undefined" ? args[number] : match;
    });
};
2
jerone

Avec sprintf.js en place, on peut faire un joli petit format

String.prototype.format = function(){
    var _args = arguments 
    Array.prototype.unshift.apply(_args,[this])
    return sprintf.apply(undefined,_args)
}   
// this gives you:
"{%1$s}{%2$s}".format("1", "0")
// {1}{0}
2
krichard

Il y a aussi Globalize.format dans le projet jQuery Globalize , le service de globalisation officiel de jQuery UI. C’est bien quand vous avez besoin d’un formatage tenant compte de la culture.

1
Craig Stuntz

J'avais besoin d'une fonction permettant de formater un prix (exprimé en centimes) de la manière préférée par l'utilisateur. Le problème, c'est que le format est spécifié par l'utilisateur - et je ne m'attends pas à ce que mes utilisateurs comprennent la syntaxe similaire à printf , ou regexps, etc. Ma solution est quelque peu similaire à celle utilisée dans Basic, de sorte que l'utilisateur ne marque qu'avec # d'emplacements pour les chiffres, par exemple:

simple_format(1234567,"$ ###,###,###.##")
"$ 12,345.67"
simple_format(1234567,"### ### ###,## pln")
"12 345,67 pln"

Je pense que cela est assez facile à comprendre par l'utilisateur et assez facile à implémenter:

function simple_format(integer,format){
  var text = "";
  for(var i=format.length;i--;){
    if(format[i]=='#'){
      text = (integer%10) + text;
      integer=Math.floor(integer/10);
      if(integer==0){
        return format.substr(0,i).replace(/#(.*#)?/,"")+text;
      }
    }else{
      text = format[i] + text;
    }
  }
  return text;
}
1
qbolec

arg fonction:

/**
 * Qt stil arg()
 * var scr = "<div id='%1' class='%2'></div>".arg("mydiv").arg("mydivClass");
 */
String.prototype.arg = function() {
    var signIndex = this.indexOf("%");
    var result = this;
    if (signIndex > -1 && arguments.length > 0) {
        var argNumber = this.charAt(signIndex + 1);
        var _arg = "%"+argNumber;
        var argCount = this.split(_arg);
        for (var itemIndex = 0; itemIndex < argCount.length; itemIndex++) {
            result = result.replace(_arg, arguments[0]);
        }
    }
    return result;
}
1
Mehmet Aydemir

Nous pouvons utiliser une bibliothèque d'opérations chaîne légère et légère String.Format pour TypeScript.

String.Format ():

var id = image.GetId()
String.Format("image_{0}.jpg", id)
output: "image_2db5da20-1c5d-4f1a-8fd4-b41e34c8c5b5.jpg";

Format de chaîne pour les spécificateurs:

var value = String.Format("{0:L}", "Apple"); //output "Apple"

value = String.Format("{0:U}", "Apple"); // output "Apple"

value = String.Format("{0:d}", "2017-01-23 00:00"); //output "23.01.2017"


value = String.Format("{0:s}", "21.03.2017 22:15:01") //output "2017-03-21T22:15:01"

value = String.Format("{0:n}", 1000000);
//output "1.000.000"

value = String.Format("{0:00}", 1);
//output "01"

Format de chaîne pour les objets, y compris les spécificateurs:

var fruit = new Fruit();
fruit.type = "Apple";
fruit.color = "RED";
fruit.shippingDate = new Date(2018, 1, 1);
fruit.amount = 10000;

String.Format("the {type:U} is {color:L} shipped on {shippingDate:s} with an amount of {amount:n}", fruit);
// output: the Apple is red shipped on 2018-01-01 with an amount of 10.000
1
Murtaza Hussain

bobjs peut le faire:

var sFormat = "My name is {0} and I am {1} years old."; 
var result = bob.string.formatString(sFormat, "Bob", 29); 
console.log(result); 
//output: 
//========== 
// My name is Bob and I am 29 years old. 
0
Tengiz

Ce n'est pas une copie exacte de sprintf; cependant, il est similaire et plus puissant: https://github.com/anywhichway/stringformatter

Les expressions de format utilisant cette bibliothèque se présentent sous la forme d'objets Javascript incorporés, par exemple.

format("I have {number: {currency: "$", precision:2}}.",50.2); 

retournera "I have $50.20.".

0
AnyWhichWay

Celui-ci fonctionne avec {0}, {1} et {}.

String.prototype.format = function format()
{                                                                                                               
  var msg = this;
  for(var i in arguments)
    msg = msg.replace(/\{\}/,arguments[i]).replace(new RegExp('\\{'+i+'\\}','g'),arguments[i]);
  return msg;
}
0
moechofe

J'ai commencé à porter JavaString.format (en fait, nouveau Formatter (). Format ()) en javascript. La version initiale est disponible à l'adresse suivante:

https://github.com/RobAu/javascript.string.format

Vous pouvez simplement ajouter le javscript et appeler StringFormat.format("%.2f", [2.4]); etc.

S'il vous plaît noter qu'il n'est pas encore terminé, mais les commentaires sont les bienvenus :)

0
RobAu
String.prototype.repeat = function(n) { 
    return new Array(++n).join(this); 
};

String.prototype.pad = function(requiredLength, paddingStr, paddingType) {    
    var n = requiredLength - this.length; 

    if (n) {
        paddingType = paddingType ? paddingType.toLowerCase() : '';
        paddingStr = paddingStr || ' ';
        paddingStr = paddingStr.repeat( Math.ceil(n / paddingStr.length) ).substr(0, n);

        if (paddingType == 'both') {
            n /= 2;
            return paddingStr.substr( 0, Math.ceil(n) ) + this + paddingStr.substr( 0, Math.floor(n) );
        }   

        if (paddingType == 'left') {
            return paddingStr + this;
        }

        return this + paddingStr;
    } 

    return this; 
}; 

// синтаксис аналогичен printf
// 'Привет, %s!'.format('мир') -> "Привет, мир!"
// '%.1s.%.1s. %s'.format('Иван', 'Иванович', 'Иванов') -> "И.И. Иванов"
String.prototype.format = function() {
    var i = 0, 
        params = arguments;

    return this.replace(/%(?:%|(?:(|[+-]+)(|0|'.+?)([1-9]\d*)?(?:\.([1-9]\d*))?)?(s|d|f))/g, function(match, sign, padding, width, precision, type) {
        if (match == '%%') { 
            return '%'; 
        }

        var v = params[i++];

        if (type == 'd') { 
            v = Math.round(v); 
        }
        else if (type == 'f') {
            v = v.toFixed(precision ? precision : 6);
        }

        if (/\+/.test(sign) && v > 0) {
            v = '+' + v;
        }

        v += '';

        if (type != 'f' && precision) {
            v = v.substr(0, precision);
        }

        if (width) {
            v = v.pad(width, padding == '' ? ' ' : padding[0] == "'" ? padding.substr(1) : padding, /-/.test(sign) ? 'right' : 'left'); 
        }

        return v;
    });
};

// this.name = 'Вася';
// console.log( 'Привет, ${name}!'.template(this) );
// "Привет, Вася!"
String.prototype.template = function(context) {
    return this.replace(/\$\{(.*?)\}/g, function(match, name) {
        return context[name];
    });
};
0
user2240578
String.prototype.format = function(){
    var final = String(this);
    for(let i=0; i<arguments.length;i++){
        final = final.replace(`%s${i+1}`, arguments[i])
    }
    return final || ''
}

console.log(("hello %s2 how %s3 you %s1").format('hi', 'hello', 'how'));
<h1 id="text">
   
</h1>
0
NISHANK KUMAR

Vous pouvez utiliser cette fonction

            String.prototype.format = function (args) {
            var str = this;
            return str.replace(String.prototype.format.regex, function(item) {
                var intVal = parseInt(item.substring(1, item.length - 1));
                var replace;
                if (intVal >= 0) {
                    replace = args[intVal];
                } else if (intVal === -1) {
                    replace = "{";
                } else if (intVal === -2) {
                    replace = "}";
                } else {
                    replace = "";
                }
                return replace;
            });
        };
        String.prototype.format.regex = new RegExp("{-?[0-9]+}", "g");

        // Sample usage.
        var str = "She {1} {0}{2} by the {0}{3}. {-1}^_^{-2}";
        str = str.format(["sea", "sells", "shells", "shore"]);
        alert(str);
0
hienbt88