JavaScript эквивалентен printf/String.Format
Я ищу хороший JavaScript-эквивалент C/PHP printf()
или для программистов на C#/Java, String.Format()
(IFormatProvider
для.NET).
Моим основным требованием является формат разделителя тысяч для чисел на данный момент, но что-то, что обрабатывает множество комбинаций (включая даты), было бы хорошо.
Я понимаю, что библиотека Ajax от Microsoft предоставляет версию String.Format()
, но нам не нужны все издержки этой платформы.
61 ответ
Я не видел pyformat в списке, поэтому я решил добавить его:
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'}
))
другое предложение - использовать строковый шаблон:
const getPathDadosCidades = (id: string) => `/clientes/${id}`
const getPathDadosCidades = (id: string, role: string) => `/clientes/${id}/roles/${role}`
/**
* 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];
}
);
}
Для использования с функциями успеха jQuery.ajax(). Передайте только один аргумент и строку замените свойствами этого объекта как {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;
};
Пример:
var userInfo = ("Email: {Email} - Phone: {Phone}").format({ Email: "someone@somewhere.com", Phone: "123-123-1234" });
Я не видел 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;
});
};
С sprintf.js на месте - можно сделать отличный маленький формат-штука
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}
Мне нужна была функция, которая могла бы отформатировать цену (указанную в центах) способом, предпочтительным для пользователя, и хитрая часть заключается в том, что формат указан пользователем - и я не ожидаю, что мои пользователи поймут синтаксис, похожий на printf или регулярные выражения и т. д. Мое решение несколько похоже на то, которое используется в Basic, поэтому пользователь просто помечает # местами для цифр, например:
simple_format(1234567,"$ ###,###,###.##")
"$ 12,345.67"
simple_format(1234567,"### ### ###,## pln")
"12 345,67 pln"
Я полагаю, что это довольно легко понять пользователю и довольно легко реализовать:
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;
}
В машинописном тексте создайте файл с именем format.ts
и импортируйте все, что вам нужно для форматирования.
// contents of format.ts
interface String {
format(...args: any[]): string;
}
if (!String.prototype.format) {
String.prototype.format = function() {
let a = this;
let b: any;
// tslint:disable-next-line: forin
for (b in arguments) {
a = a.replace(/%[a-z]/, arguments[b]);
}
return a;
};
}
Для форматирования строки используйте этот код:
import './format';
console.log('Hello, %s!'.format('World'));
пример
String.prototype.format = function() {
let a = this;
let b;
for (b in arguments) {
a = a.replace(/%[a-z]/, arguments[b]);
}
return a;
};
console.log('Hello, %s!'.format('World'));
Если вам просто нужно отформатировать строку только с помощью спецификатора%s
function _sprintf(message){
const regexp = RegExp('%s','g');
let match;
let index = 1;
while((match = regexp.exec(message)) !== null) {
let replacement = arguments[index];
if (replacement) {
let messageToArray = message.split('');
messageToArray.splice(match.index, regexp.lastIndex - match.index, replacement);
message = messageToArray.join('');
index++;
} else {
break;
}
}
return message;
}
_sprintf("my name is %s, my age is %s", "bob", 50); // my name is bob, my age is 50
arg
функция:
/**
* 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;
}
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>
Вот очень короткая функция, которая выполняет подмножество printf и показывает результат в консоли разработчика:
function L(...values)
{
// Replace each '@', starting with the text in the first arg
console.log(values.reduce(function(str,arg) {return str.replace(/@/,arg)}));
} // L
Вот тест:
let a=[1,2,3];
L('a: [@]',a);
Вывод похож на:a=[1,2,3]
Если вам нужен printf, используйте printf
Похоже, 90% комментаторов никогда не использовали printf с более сложным форматом, чем просто%d. Интересно, как они выводят, например, денежные значения?
Итак, сначала мы настроим некоторые переменные для использования:
const date = new Date();
const locale = 'en-us';
const wDay = date.toLocaleString(locale, {weekday: 'short'});
const month = date.toLocaleString(locale, {month: 'long'});
const year = date.toLocaleString(locale, {year: 'numeric'});
const minute = date.toLocaleString(locale, {minute: 'numeric'});
const [hour, ap] = date.toLocaleString(locale, {hour: 'numeric', hour12:true}).split(' ');
let mDay = date.toLocaleString(locale, {day: 'numeric'});
switch(mDay % 10)
{
case 1: mDay += 'st'; break;
case 2: mDay += 'nd'; break;
case 3: mDay += 'rd'; break;
default: mDay += 'th'; break;
}
Теперь, когда у нас есть все это, мы можем отформатировать строку следующим образом:
const formatter = (...a) => `${a[0]}, the ${a[1]} of ${a[2]} ${a[3]} at ${a[4]}:${a[5]} ${a[6]}`;
const formatted = formatter(wDay, mDay, month, year, hour, minute, ap);
Мы могли бы даже использовать именованные параметры для функции "форматирования":
const formatter = (wDay, mDay, month, year, hour, minute, ap) => `${wDay}, the ${mDay} of ${month} ${year} at ${hour}:${minute} ${ap}`;
const formatted = formatter(wDay, mDay, month, year, hour, minute, ap);
Если вы заметили, оба приведенных выше JS-шаблона являются результатом обратных вызовов. Если бы весь приведенный выше фрагмент кода был инкапсулирован в функцию, которая должна была возвращать отформатированную дату, было бы несложно представить, как таким же образом сконструировать произвольную функцию «форматировщика», которую можно было бы передать извне.
tl;dr вы можете повторно использовать шаблонные литералы, если вы поместите их в обратные вызовы и используете аргументы в качестве замены.
Я использую литеральный подход шаблона, как показано ниже:
export const messages = {
foo: (arg1, arg2) => `Hello ${arg1} ${arg2}`,
bar: (arg1) => `Hello ${arg1}`,
}
Из файла:
console.log(messages.foo('Bar', 'World'))
console.log(messages.bar('Foo'))
Существует также Globalize.format
в проекте jQuery Globalize, официальный сервис глобализации для пользовательского интерфейса jQuery. Это хорошо, когда вам нужно культурно-ориентированное форматирование.
Этот работает с {0}, {1} и {}.
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;
}
Мне нужно было решение на шаг вперед.
Шаблон, который я мог бы повторно использовать для генерации строк не только в объявлении, но и в случайное время во время выполнения.
Итак, я наткнулся на этот джиг:
class Texplate{
constructor(...args){
this.data = args;
}
apply(...args){
var text = "";
var i = 0, j = 0, n = this.data.length, m = args.length;
for(;i < n && j < m; i++, j++){
text += this.data[i] + args[j];
}
for (; i < n; i++){
text += this.data[i];
}
for (; j < m; j++){
text += args[j];
}
return text;
}
}
Это позволяет создать текстовый шаблон, который работает внутри как алгоритм слияния массивов, начиная с текстового массива, определенного в конструкторе.
Пример использования:
var Textplate example = new Texplate("Hello, ", "!");
console.log(example.apply("Frank"));
console.log(example.apply("Mary"));
console.log(example.apply());
console.log(example.apply("Frank", " Have a good day!"));
Я отвечаю на этот вопрос по следующим причинам.
- sprintf / printf позволяет вам предоставлять аргументы переменной длины.
- В самых популярных ответах используются литералы шаблонов . При использовании литералов шаблона вы должны знать количество имеющихся у вас аргументов.
Ответы @Braden Best и @David Spector кажутся обоснованными с моей точки зрения.
Я добавляю следующий ответ, чтобы кто-то мог найти ответ в одном месте.
Объяснение:
- В этом методе вы передаете желаемую строку шаблона в первом параметре, имеющем заполнитель. Кроме того, вы можете передать столько заменителей, сколько захотите.
- Затем он перебирает переданные значения и заменяет следующее текущим итерируемым значением.
В основном, если вы знаете, что делают Array.reduce и String.replace , вы понимаете код.
Вы можете изменить на все, что захотите. Кроме того, вам необходимо будет изменить
:param
в этом случае внутри метода sprintf.
Я начал портировать Java
String.format
(фактически новый Formatter().format()) для JavaScript. Начальная версия доступна по адресу:
https://github.com/RobAu/javascript.string.format
Вы можете просто добавить JavaScript и вызвать StringFormat.format("%.2f", [2.4]);
и т.п.
Обратите внимание, что это еще не закончено, но отзывы приветствуются:)
Модифицированный код старого ответа /questions/8562252/javascript-ekvivalenten-printfstringformat/8562281#8562281 намного эффективнее (без медленного RegExp) и короче
String.prototype.formatUnicorn = function () {
let str = this.toString();
if(!arguments.length) {
return;
};
const [args] = arguments;
for (const key of Object.keys(args)) {
str = str.replaceAll(`{${key}}`, args[key]);
};
return str;
};
Применение:
"{test} {test_2} {test}".formatUnicorn({"test": "hello", "test_2": "world"}); // yields hello world hello
эталон между новым и старым: https://jsben.ch/BRovx
bobjs может сделать это:
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.
export function stringFormate (str: string, ...args: string[]) {
return args.reduce((acc, curr, i) => acc.replace(new RegExp("\\{" + i + "\\}", 'g'), curr), str);
}
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];
});
};
Вы можете использовать эту функцию
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);
Просто используйте шаблонные строки и стрелочные функции. Это даже делает их многоразовыми.
Это реализация /questions/8562252/javascript-ekvivalenten-printfstringformat/8562277#8562277 для CoffeeScript.
https://gist.github.com/eces/5669361
if String.prototype.format is undefined
String.prototype.format = () ->
_arguments = arguments
this.replace /{(\d+)}/g, (match, number) ->
if typeof _arguments[number] isnt 'undefined' then _arguments[number] else match
Не самая рекомендуемая функция в мире, но работает.
Если вам нужен sprintf, просто скопируйте и вставьте эту же функцию и измените return console.log(sb)
чтобы просто return sb
.
printf = function(s, /*args...*/) {
a = arguments;
al = a.length;
if (al <= 1) return -2;
if (al >= 2 && s.toLowerCase().search(/%[a-z]/) == -1) return -1;
sb = s;
for (i = 1; i <= al - 1; i++) {
sb = sb.replace(/%[a-z]/, a[i]);
}
return console.log(sb);
}
var someString = "Hello %s\nIt's %s:%s %s now.\nThe day is %s\n";
printf(someString, "StackruUser", "5", "48", "PM", "beautiful");
Аналог функции sprintf() в JavaScript как фильтр Vue и расширение String.prototype.format():
/**
* Returns a formatted string.
*
* @param template
* @param values
* @return string
*/
String.format = function (template, ...values) {
let i = -1;
function callback(exp, p0, p1, p2, p3, p4) {
if (exp === '%%') return '%';
if (values[++i] === undefined) return undefined;
exp = p2 ? parseInt(p2.substr(1)) : undefined;
let base = p3 ? parseInt(p3.substr(1)) : undefined;
let val;
switch (p4) {
case 's': val = values[i]; break;
case 'c': val = values[i][0]; break;
case 'f': val = parseFloat(values[i]).toFixed(exp); break;
case 'p': val = parseFloat(values[i]).toPrecision(exp); break;
case 'e': val = parseFloat(values[i]).toExponential(exp); break;
case 'x': val = parseInt(values[i]).toString(base ? base : 16); break;
case 'd': val = parseFloat(parseInt(values[i], base ? base : 10).toPrecision(exp)).toFixed(0); break;
}
val = typeof (val) == 'object' ? JSON.stringify(val) : val.toString(base);
let sz = parseInt(p1); /* padding size */
let ch = p1 && p1[0] === '0' ? '0' : ' '; /* isnull? */
while (val.length < sz) val = p0 !== undefined ? val + ch : ch + val; /* isminus? */
return val;
}
let regex = /%(-)?(0?[0-9]+)?([.][0-9]+)?([#][0-9]+)?([scfpexd%])/g;
return template.replace(regex, callback);
}
String.prototype.format = function() {
return String.format(this, ...arguments);
}
const StringFormat = {
install: (Vue, options) => {
Vue.filter('format', function () {
return String.format(...arguments);
});
},
};
export default StringFormat;
Исходный ответ: эквивалент JavaScript printf/String.Format