JavaScript эквивалентен printf / String.Format - PullRequest
1785 голосов
/ 04 марта 2009

Я ищу хороший JavaScript-эквивалент C / PHP printf() или для программистов на C # / Java, String.Format() (IFormatProvider для .NET).

Мое основное требование на данный момент - это формат разделителя тысяч для чисел, но то, что обрабатывает множество комбинаций (включая даты), будет хорошо.

Я понимаю, что Microsoft Ajax предоставляет версию String.Format(), но нам не нужны все издержки этой инфраструктуры.

Ответы [ 45 ]

1340 голосов
/ 12 января 2011

Опираясь на ранее предложенные решения:

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

выходы

ASP мертв, но ASP.NET жив! ASP {2}


Если вы предпочитаете не изменять прототип 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
      ;
    });
  };
}

Дает вам гораздо более знакомое:

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

с тем же результатом:

ASP мертв, но ASP.NET жив! ASP {2}

894 голосов
/ 04 марта 2009

Начиная с ES6 вы можете использовать строки шаблона:

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

Подробнее см. Ответ Ким ниже.


В противном случае:

Попробуйте sprintf () для JavaScript .


Если вы действительно хотите использовать простой метод форматирования самостоятельно, не выполняйте замены последовательно, а выполняйте их одновременно.

Поскольку большинство других упомянутых предложений терпят неудачу, когда строка замены предыдущей замены также содержит последовательность формата, подобную этой:

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

Обычно вы ожидаете, что выходной сигнал будет {1}{0}, но фактический выходной сигнал равен {1}{1}. Так что вместо этого сделайте одновременную замену, как в предложении страха .

420 голосов
/ 14 августа 2013

Забавно, потому что Stack Overflow фактически имеет свою собственную функцию форматирования для прототипа String с именем formatUnicorn. Попытайся! Зайдите в консоль и наберите что-то вроде:

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

Firebug

Вы получите этот вывод:

Hello, Gabriel, are you feeling OK?

Вы можете использовать объекты, массивы и строки в качестве аргументов! Я получил его код и переработал его для создания новой версии 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;
};

Обратите внимание на умный вызов Array.prototype.slice.call(arguments) - это означает, что если вы добавите аргументы, которые представляют собой строки или числа, а не один объект в стиле JSON, вы получите поведение C # String.Format почти точно. 1022 *

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

Это потому, что Array slice заставит все, что находится в arguments в Array, независимо от того, было это изначально или нет, и key будет индексом (0, 1, 2 .. .) каждого элемента массива, приведенного к строке (например, «0», поэтому "\\{0\\}" для вашего первого шаблона регулярного выражения).

Ухоженная.

303 голосов
/ 12 августа 2011

Форматирование чисел в JavaScript

Я попал на эту страницу с вопросом в надежде найти способ форматировать числа в JavaScript, не добавляя еще одну библиотеку. Вот что я нашел:

Округление чисел с плавающей точкой

Эквивалент sprintf("%.2f", num) в JavaScript выглядит как num.toFixed(2), который форматирует num до 2 десятичных знаков с округлением (но см. Комментарий @ ars265 о Math.round ниже).

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

Экспоненциальная форма

Эквивалент sprintf("%.2e", num) равен num.toExponential(2).

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

Шестнадцатеричные и другие основания

Чтобы напечатать числа в базе B, попробуйте num.toString(B). JavaScript поддерживает автоматическое преобразование в и из баз со 2 по 36 (кроме того, некоторые браузеры имеют ограниченную поддержку для кодировки base64 ).

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

Справочные страницы

Краткое руководство по форматированию номеров JS

Справочная страница Mozilla для toFixed () (со ссылками на toPrecision (), toExponential (), toLocaleString (), ...)

210 голосов
/ 25 августа 2015

Начиная с ES6 вы можете использовать шаблонные строки :

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

Имейте в виду, что строки шаблона окружены обратными чертами `вместо (одинарных) кавычек.

Для получения дополнительной информации:

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

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

Примечание: Посетите сайт mozilla, чтобы найти список поддерживаемых браузеров.

170 голосов
/ 23 ноября 2010

jsxt, Zippo

Этот вариант подходит лучше.

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

С помощью этой опции я могу заменить строки следующим образом:

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

С вашим кодом вторая {0} не будет заменена. ;)

103 голосов
/ 16 августа 2010

Я использую эту простую функцию:

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

Это очень похоже на string.format:

"{0} is dead, but {1} is alive!".format("ASP", "ASP.NET")
60 голосов
/ 15 апреля 2014

Для Node.js пользователей существует util.format, который имеет printf-подобную функциональность:

util.format("%s world", "Hello")
49 голосов
/ 25 января 2011

Вот минимальная реализация sprintf в JavaScript: он выполняет только "% s" и "% d", но я оставил место для его расширения. Это бесполезно для ОП, но другие люди, которые натыкаются на эту ветку из Google, могут извлечь из этого пользу.

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

Пример:

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

В отличие от аналогичных решений в предыдущих ответах, этот выполняет все замены за один раз , поэтому он не заменит части ранее замененных значений.

48 голосов
/ 23 июня 2015

Я удивлен, что никто не использовал reduce, это встроенная краткая и мощная функция JavaScript.

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

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" Как это работает: уменьшение применяет функцию к аккумулятору и каждому элементу массива (слева направо), чтобы уменьшить его до одного значения. 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") );

...