Отформатировать строку JavaScript, используя заполнители и объект подстановки?


92

У меня есть строка с надписью: My Name is %NAME% and my age is %AGE%.

%XXX%заполнители. Нам нужно подставить туда значения из объекта.

Объект выглядит так: {"%NAME%":"Mike","%AGE%":"26","%EVENT%":"20"}

Мне нужно проанализировать объект и заменить строку соответствующими значениями. Итак, окончательный результат будет:

Меня зовут Майк, мне 26 лет.

Все это должно быть выполнено либо с использованием чистого javascript, либо jquery.


2
Это больше похоже на объект, чем на массив
Джоэл Кохорн

3
что ты уже испробовал? Вы смотрели на метод string .replace () ? (Кроме того, у вас там нет массива, у вас есть объект.)
nnnnnn

1
Это довольно некрасиво. Неужели вы так же хорошо обслуживаете {NAME: "Mike", AGE: 26, EVENT: 20}? Конечно, вам все равно потребуется, чтобы эти ключи отображались в строке ввода с пометкой «процент».
davidchambers

Ответы:


152

Требования исходного вопроса явно не могли выиграть от интерполяции строк, поскольку кажется, что это обработка произвольных ключей замены во время выполнения.

Однако , если вам просто нужно было выполнить интерполяцию строк, вы можете использовать:

const str = `My name is ${replacements.name} and my age is ${replacements.age}.`

Обратите внимание на обратные кавычки, ограничивающие строку, они обязательны.


Для ответа, соответствующего конкретным требованиям OP, вы можете использовать String.prototype.replace()для замен.

Следующий код будет обрабатывать все совпадения, а не трогать их без замены (если все ваши заменяемые значения являются строками, в противном случае см. Ниже).

var replacements = {"%NAME%":"Mike","%AGE%":"26","%EVENT%":"20"},
    str = 'My Name is %NAME% and my age is %AGE%.';

str = str.replace(/%\w+%/g, function(all) {
   return replacements[all] || all;
});

jsFiddle .

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

jsFiddle .

Однако, если ваш формат не имеет специального формата, то есть какой-либо строки, и ваш объект замены не имеет nullпрототипа, используйте Object.prototype.hasOwnProperty(), если вы не можете гарантировать, что ни одна из ваших потенциально заменяемых подстрок не будет конфликтовать с именами свойств в прототипе.

jsFiddle .

В противном случае, если бы ваша строка для замены была 'hasOwnProperty'такой, вы бы получили неверную строку.

jsFiddle .


В качестве примечания, вас следует называть replacementsan Object, а не Array.


2
+1. Ницца. Хотя вы можете сказать, return replacements[all] || allчтобы покрыть %NotInReplacementsList%случаи.
nnnnnn

6
Это не сработает, если значение замены ложное. Так что лучше использовать это выражение возврата:return all in params ? params[all] : all;
Michael Härtl

@ MichaelHärtl Разве ваши замены не должны быть строками? Если вы хотите заменить пустую строку, лучше проверить другими способами.
Alex

1
@alex У меня была ситуация, когда замены также могли быть целыми числами и даже 0. В этом случае это не сработало.
Michael Härtl

@ MichaelHärtl Обновлено, чтобы охватить этот случай.
Alex

24

Как насчет использования шаблонных литералов ES6?

var a = "cat";
var b = "fat";
console.log(`my ${a} is ${b}`); //notice back-ticked string

Подробнее о шаблонных литералах ...


5
Если у вас есть объект с заполнителями, например OP, как в этом помогает строковая интерполяция?
Alex

Работает как шарм! Самое прагматичное решение моих проблем с размещением мест, идеальное.
BAERUS

Это решение не работает для замен во время выполнения
Тьерри Дж.

13

Вы можете использовать JQuery (jquery.validate.js), чтобы он работал легко.

$.validator.format("My name is {0}, I'm {1} years old",["Bob","23"]);

Или, если вы хотите использовать только эту функцию, вы можете определить эту функцию и просто использовать ее как

function format(source, params) {
    $.each(params,function (i, n) {
        source = source.replace(new RegExp("\\{" + i + "\\}", "g"), n);
    })
    return source;
}
alert(format("{0} is a {1}", ["Michael", "Guy"]));

кредит команде jquery.validate.js


1
Вы определенно не захотите загружать этот плагин только для этого, но я уже использую его для проверки формы на странице ... так что спасибо за совет!
nabrown

1
Довольно неэффективно создавать регулярное выражение для каждого числа, было бы лучше сопоставить все числа, а затем заменить, если значение было найдено в массиве, возможно?
Alex

для тех, кто заинтересован, это происходит здесь: github.com/jquery-validation/jquery-validation/blob/master/src/…
Raphael C

1
+ очень хорошо ... и $.eachвы можете сделать String.prototype.format=function(p){var s=this,r=function(v,i){s=s.replace(new RegExp("\\{"+i+"\\}","g"),v);};p.forEach(r);return s;}так, чтобы вам не нужно было включать jquery только для этого;)
Larphoid

11

Как современным браузером, заполнитель поддерживаются новой версией Chrome / Firefox, подобно как функция типа C printf().

Заполнители:

  • %s Строка.
  • %d, %iЦелое число.
  • %f Число с плавающей запятой.
  • %o Гиперссылка на объект.

например

console.log("generation 0:\t%f, %f, %f", a1a1, a1a2, a2a2);

Кстати, чтобы увидеть результат:

  • В Chrome используйте ярлык Ctrl + Shift + Jили, F12чтобы открыть инструмент разработчика.
  • В Firefox используйте ярлык Ctrl + Shift + Kили, F12чтобы открыть инструмент разработчика.

@Update - поддержка nodejs

Кажется, что nodejs не поддерживает %f, вместо этого можно использовать %dnodejs. С %dчислом будет напечатано как число с плавающей запятой, а не как целое.


6

Просто используйте replace()

var values = {"%NAME%":"Mike","%AGE%":"26","%EVENT%":"20"};
var substitutedString = "My Name is %NAME% and my age is %AGE%.".replace("%NAME%", $values["%NAME%"]).replace("%AGE%", $values["%AGE%"]);

3
обязательно «используйте MDN в качестве справочника»: developer.mozilla.org/en/JavaScript/Reference/Global_Objects/…
mu слишком короткое

2
Спасибо за порку, парни - оценено;)
hafichuk 02

5

Вы можете использовать настраиваемую функцию замены, например:

var str = "My Name is %NAME% and my age is %AGE%.";
var replaceData = {"%NAME%":"Mike","%AGE%":"26","%EVENT%":"20"};

function substitute(str, data) {
    var output = str.replace(/%[^%]+%/g, function(match) {
        if (match in data) {
            return(data[match]);
        } else {
            return("");
        }
    });
    return(output);
}

var output = substitute(str, replaceData);

Вы можете увидеть его работу здесь: http://jsfiddle.net/jfriend00/DyCwk/ .


1
Круто, Алекс сделал почти то же самое, но в меньшем количестве строк кода (хотя тернарные операторы, вероятно, медленнее, чем if..else).
RobG

Эй, я поставил тебе +1! Вы оба выполнили функцию замены, ваша не совсем такая же, но очень похожая. Ваш RegExp тоже отличается, OP было бы лучше использовать %% или $$ или аналогичные в качестве разделителей - одиночный% или% обычно встречается в строке, но двойники маловероятны.
RobG 02

4

Если вы хотите сделать что-то ближе к console.log, например, заменить заполнители% s, как в

>console.log("Hello %s how are you %s is everything %s?", "Loreto", "today", "allright")
>Hello Loreto how are you today is everything allright?

Я написал это

function log() {
  var args = Array.prototype.slice.call(arguments);
  var rep= args.slice(1, args.length);
  var i=0;
  var output = args[0].replace(/%s/g, function(match,idx) {
    var subst=rep.slice(i, ++i);
    return( subst );
  });
   return(output);
}
res=log("Hello %s how are you %s is everything %s?", "Loreto", "today", "allright");
document.getElementById("console").innerHTML=res;
<span id="console"/>

ты получишь

>log("Hello %s how are you %s is everything %s?", "Loreto", "today", "allright")
>"Hello Loreto how are you today is everything allright?"

ОБНОВИТЬ

Я добавил простой вариант, который String.prototypeполезен при преобразовании строк, вот он:

String.prototype.log = function() {
    var args = Array.prototype.slice.call(arguments);
    var rep= args.slice(0, args.length);
    var i=0;
    var output = this.replace(/%s|%d|%f|%@/g, function(match,idx) {
      var subst=rep.slice(i, ++i);
      return( subst );
    });
    return output;
   }

В этом случае вы сделаете

"Hello %s how are you %s is everything %s?".log("Loreto", "today", "allright")
"Hello Loreto how are you today is everything allright?"

Попробуйте эту версию здесь


2
я сделал изменения на вашей функцию без прототипов formatMessage(message: string, values: string[]) { let i = 0; return message.replace(/%\w+%/g, (match, idx) => { return values[i++]; }); } это займет сообщение для формата и массива заменить значения и ищет%SOME_VALUE%
баку

4

В настоящее время в Javascript по-прежнему нет собственного решения для этого поведения. Шаблоны с тегами связаны между собой, но не решают эту проблему.

Здесь есть рефактор решения alex с целью замены.

В решении используются стрелочные функции и аналогичный синтаксис для заполнителей, что и встроенная интерполяция Javascript в шаблонных литералах ( {}вместо %%). Также нет необходимости включать разделители ( %) в названия замен.

Есть два варианта: описательный и сокращенный.

Описательное решение:

const stringWithPlaceholders = 'My Name is {name} and my age is {age}.';

const replacements = {
  name: 'Mike',
  age: '26',
};

const string = stringWithPlaceholders.replace(
  /{\w+}/g,
  placeholderWithDelimiters => {
    const placeholderWithoutDelimiters = placeholderWithDelimiters.substring(
      1,
      placeholderWithDelimiters.length - 1,
    );
    const stringReplacement = replacements[placeholderWithoutDelimiters] || placeholderWithDelimiters;
    return stringReplacement;
  },
);

console.log(string);

Сокращенное решение:

const stringWithPlaceholders = 'My Name is {name} and my age is {age}.';

const replacements = {
  name: 'Mike',
  age: '26',
};

const string = stringWithPlaceholders.replace(/{\w+}/g, placeholder =>
  replacements[placeholder.substring(1, placeholder.length - 1)] || placeholder,
);

console.log(string);


1
Спасибо за это, здорово иметь общее решение для строки-заполнителя и объекта, который можно слить с ней, вот так
Карлос П.

@CarlosP, вот в чем идея - иметь общее решение. Но я думаю, что это должно быть что-то родное для языка, так как это обычный вариант использования.
AMS777,

1
Это можно немного упростить, используя такие группы регулярных выражений:stringWithPlaceholders.replace(/{(\w+)}/g, (fullMatch, group1) => replacements[group1] || fullMatch )
Kade

2

Это позволяет вам делать именно это

НПМ: https://www.npmjs.com/package/stringinject

GitHub: https://github.com/tjcafferkey/stringinject

Сделав следующее:

var str = stringInject("My username is {username} on {platform}", { username: "tjcafferkey", platform: "GitHub" });

// My username is tjcafferkey on Git

2
Но поскольку вы можете сделать это в es6, это, вероятно, немного перебор?
IonicBurger

1
Это позволяет хранить строку в одном месте в одном формате, а затем позже заменять соответствующие элементы, используя только одну функцию. Насколько мне известно, это невозможно сделать с литералами шаблона es6. Например, для этого можно использовать строки перевода, где вы будете использовать строку в другом месте и вставлять туда желаемые значения.
Johan Persson

2

Вот еще один способ сделать это - динамически использовать литералы шаблона es6 во время выполнения.

const str = 'My name is ${name} and my age is ${age}.'
const obj = {name:'Simon', age:'33'}


const result = new Function('const {' + Object.keys(obj).join(',') + '} = this.obj;return `' + str + '`').call({obj})

document.body.innerHTML = result


1

В качестве быстрого примера:

var name = 'jack';
var age = 40;
console.log('%s is %d yrs old',name,age);

Результат:

Джеку 40 лет


7
Это здорово, если вы не хотите делать что-то, кроме регистрации в консоли.
Alex

13
не должно быть console.log?
drzaus

0
const stringInject = (str = '', obj = {}) => {
  let newStr = str;
  Object.keys(obj).forEach((key) => {
    let placeHolder = `#${key}#`;
    if(newStr.includes(placeHolder)) {
      newStr = newStr.replace(placeHolder, obj[key] || " ");
    }
  });
  return newStr;
}
Input: stringInject("Hi #name#, How are you?", {name: "Ram"});
Output: "Hi Ram, How are you?"

0

Я написал код, который позволяет легко форматировать строку.

Воспользуйтесь этой функцией.

function format() {
    if (arguments.length === 0) {
        throw "No arguments";
    }
    const string = arguments[0];
    const lst = string.split("{}");
    if (lst.length !== arguments.length) {
        throw "Placeholder format mismatched";
    }
    let string2 = "";
    let off = 1;
    for (let i = 0; i < lst.length; i++) {
        if (off < arguments.length) {
            string2 += lst[i] + arguments[off++]
        } else {
            string2 += lst[i]
        }
    }
    return string2;
}

пример

format('My Name is {} and my age is {}', 'Mike', 26);

Выход

Меня зовут Майк, мне 26 лет

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.