JavaScript équivalent à printf / String.Format

je cherche un bon équivalent JavaScript du C/PHP printf() ou pour les programmeurs C#/Java, String.Format() ( IFormatProvider pour .NET).

mon exigence de base est un format de séparateur de mille pour les nombres pour le moment, mais quelque chose qui gère beaucoup de combinaisons (y compris les dates) serait bon.

je me rends compte que la bibliothèque de Microsoft Ajax fournit une version de String.Format() , mais nous ne voulons pas de la totalité les frais généraux du cadre de référence.

1629
demandé sur Chris S 2009-03-04 15:53:02

30 réponses

modifier: à partir de ES6 sur vous pourriez utiliser des chaînes de template:

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

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

réponse originale:

Essayer sprintf() de JavaScript .


mettre à jour Ok, si vous voulez vraiment faire une méthode de format simple sur votre propre, ne pas faire les remplacements successivement mais ne simultanément.

parce que la plupart des autres propositions qui sont mentionnées échouent quand une chaîne de remplacement du remplacement précédent contient aussi une séquence de format comme ceci:

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

normalement, vous vous attendez à ce que la sortie soit {1}{0} mais la sortie réelle est {1}{1} . Alors faites un remplacement simultané à la place comme dans la suggestion de fearphage .

720
répondu Gumbo 2018-09-02 11:31:48

S'appuyant 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")

sorties

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


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

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

1289
répondu fearphage 2016-06-29 16:25:30

c'est drôle parce que Stack Overflow a en fait sa propre fonction de formatage pour le prototype String appelé formatUnicorn . L'essayer! Allez dans la console et tapez quelque chose comme:

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

Firebug

vous obtenez ce résultat:

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 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 intelligent Array.prototype.slice.call(arguments) -- cela signifie que si vous lancez des arguments qui sont des chaînes ou des nombres, pas un seul objet de style JSON, vous obtenez C#'S String.Format comportement presque exactement.

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

c'est parce que Array 's slice va forcer tout ce qui est dans arguments dans un Array , qu'il était à l'origine ou non, et le key sera l'indice (0, 1, 2...) de chaque élément de tableau contraint dans une chaîne (par exemple," 0", donc "\{0\}" pour votre premier motif regexp).

Neat.

379
répondu Gabriel Nahmias 2017-01-13 15:27:51

formatage du numéro en JavaScript

je suis arrivé à cette page de question en espérant trouver comment numéros de format en JavaScript, sans introduire encore une autre bibliothèque. Voici ce que j'ai trouvé:

Arrondissement des nombres à virgule flottante

l'équivalent de sprintf("%.2f", num) en JavaScript semble être num.toFixed(2) , qui formats num à 2 décimales, avec arrondi (mais voir @ars265 commentaire à propos de 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"

bases hexadécimales et autres

pour imprimer les numéros de la base B, essayez num.toString(B) . JavaScript prend en charge la conversion automatique vers et depuis les bases 2 à 36 (en outre, certains navigateurs ont prise en charge limitée pour le codage de base64 ).

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

Pages De Référence

tutoriel rapide sur le formatage du numéro JS

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

291
répondu rescdsk 2018-01-29 16:15:53

De l'ES6 sur, vous pourriez utiliser chaînes du modèle :

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

soyez conscient que les chaînes de template sont entourées de bascules ` au lieu de (simple) guillemets.

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

Note: Consultez le site mozilla pour trouver une liste des navigateurs pris en charge.

174
répondu Kim 2016-08-22 17:46:30

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 serait pas remplacé. ;)

169
répondu Filipiz 2015-05-07 11:29:46

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")
93
répondu Zippoxer 2014-07-10 23:49:12

voici un minimal implémentation de sprintf en JavaScript: il ne fait que "%s "et" %d", mais j'ai laissé de la place pour qu'il soit étendu. Il est inutile à L'OP, mais d'autres personnes qui trébuchent à travers ce fil venant de Google pourraient en bénéficier.

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 à des solutions similaires dans les réponses précédentes, celle-ci fait toutes les substitutions en une seule go , de sorte qu'il ne remplacera pas des parties de valeurs précédemment remplacées.

48
répondu Luke Madhanga 2015-03-06 21:18:17

Pour Noeud.js les utilisateurs il y a util.format qui a printf fonctionnalité:

util.format("%s world", "Hello")
47
répondu George Eracleous 2017-10-09 02:10:12

je suis surpris que personne n'ait utilisé reduce , il s'agit d'une fonction JavaScript concise et puissante native.

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 cela fonctionne:

réduire applique une fonction à l'encontre d'un accumulateur et chaque élément de la matrice (de gauche à droite) réduire à une seule valeur.

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")
);
41
répondu CPHPython 2018-02-21 14:50:51

les programmeurs JavaScript peuvent utiliser la chaîne de caractères.prototype.sprintf à https://github.com/ildar-shaimordanov/jsxt/blob/master/js/String.js . En voici un exemple:

var d = new Date();
var dateStr = '%02d:%02d:%02d'.sprintf(
    d.getHours(), 
    d.getMinutes(), 
    d.getSeconds());
30
répondu jsxt 2016-11-20 10:51:39

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

String.prototype.format = function() {
    var formatted = this;
    for (var arg in arguments) {
        formatted = formatted.replace("{" + arg + "}", arguments[arg]);
    }
    return formatted;
};
20
répondu user437231 2014-07-10 23:50:07

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 aussi une version non prototype que j'utilise plus souvent pour sa syntaxe 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

ES 2015 mise à jour

tous les nouveaux trucs cool EN ES 2015 rend cela beaucoup plus facile:

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

j'ai pensé que puisque ceci, comme les plus anciens, ne parsemble pas réellement les lettres, il pourrait aussi bien utiliser un jeton unique %% . Cela a 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 devez le remplacer par lui-même:

format("I love percentage signs! %%", "%%");
// "I love percentage signs! %%"
16
répondu Braden Best 2018-08-01 20:59:12

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
répondu lior hakim 2015-01-02 10:29:06

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

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

14
répondu Chris S 2017-03-27 19:12:44

j'utilise une petite bibliothèque appelée chaîne.format pour JavaScript qui supporte la plupart des capacités de la chaîne de format (y compris le format des nombres et des dates), et utilise la syntaxe .NET. Le script lui-même est plus petit que 4 kB, donc il ne crée pas beaucoup de overhead.

13
répondu Sven N 2009-09-27 08:36:00

si vous cherchez à manipuler le séparateur de milliers, vous devez vraiment utiliser toLocaleString() de la classe JavaScript nombre car il formatera la chaîne de caractères pour la région de l'utilisateur.

la classe JavaScript Date peut formater des dates et des heures localisées.

10
répondu 17 of 26 2014-07-10 23:48:13

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 pour gratuit. Définir 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 traitant de la sortie, il ne doit pas être super 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'
10
répondu Rtlprmft 2018-05-29 12:55:32

le PHPJS project a écrit des implémentations JavaScript pour de nombreuses fonctions de PHP. Puisque la fonction sprintf() de PHP est fondamentalement la même que celle de C printf() , leur implémentation JavaScript De it devrait satisfaire vos besoins.

8
répondu Spudley 2014-07-10 23:52:19

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
répondu Steven Penny 2014-08-14 07:01:49

une version très légèrement différente, celle que je préfère (celle-ci utilise des arguments {xxx} tokens plutôt que des arguments {0} numérotés, c'est beaucoup plus auto-documentant et convient beaucoup 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 variante serait:

  var formatted = l(this);

qui appelle d'abord une fonction de localisation l ().

7
répondu Peter 2012-10-11 15:40:03

J'ai une solution très proche de celle de Peter, mais elle traite du cas du nombre et 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 qu'il pourrait être encore mieux de traiter les cas tous les deeps, 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 cool si vous utilisez des traductions dans des cadres de gabarits comme AngularJS :

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

Où la fr.json est quelque chose comme

{
    "hello-message": "Hello {name}, welcome.",
    "hello-by-name": "Hello {0}, welcome."
}
6
répondu Thiago Mata 2014-09-30 17:55:27

pour ceux qui aiment noeud.JS et son util.format fonctionnalité, je viens de l'extraire dans sa forme JavaScript vanille (avec seulement des fonctions qui util.utilisation du format):

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é à partir de: https://github.com/joyent/node/blob/master/lib/util.js

6
répondu A T 2015-01-23 04:47:21

il y a "sprintf" pour JavaScript que vous pouvez trouver à http://www.webtoolkit.info/javascript-sprintf.html .

5
répondu Pooria 2014-07-10 23:47:33

j'ai un formater légèrement plus long pour JavaScript ici ...

vous pouvez faire le formatage de plusieurs façons:

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

aussi, si vous avez dit une ObjectBase.prototype.format (comme avec DateJS ) il utilisera que.

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 aussi aliasé avec .asFormat et avoir un peu de détection en place au cas où il y a déjà une chaîne.format (comme avec la boîte à outils de MS Ajax (je déteste cette bibliothèque).

5
répondu Tracker1 2014-07-10 23:56:28

juste au cas où quelqu'un a besoin d'une fonction pour empêcher la portée globale polluante, 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
répondu Afshin Mehrabani 2015-01-20 09:15:57

pour le formatage de base:

var template = jQuery.validator.format("{0} is not a valid value");
var result = template("abc");
5
répondu Evgeny Gerbut 2015-12-08 14:18:22

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
répondu jerone 2012-10-10 07:53:36

Je n'ai pas vu pyformat dans la liste donc j'ai pensé que j'allais le jeter dans:

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
répondu Bovard 2014-07-24 20:05:27
/**
 * 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];
        }
    );
}
2
répondu LayZee 2016-06-22 06:21:11