Форматувати рядок JavaScript, використовуючи заповнювачі та об’єкт заміни?


92

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

%XXX%є заповнювачами. Нам потрібно замінити там значення з об’єкта.

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

Мені потрібно проаналізувати об’єкт і замінити рядок відповідними значеннями. Таким чином, кінцевий результат буде:

Мене звуть Майк і мені 26 років.

Все це потрібно зробити або за допомогою чистого javascript, або jquery.


2
Це більше схоже на об'єкт, ніж на масив
Джоел Кегорн

3
Що ви пробували дотепер? Ви розглядали метод .replace () рядка ? (Крім того, у вас там немає масиву, у вас є об’єкт.)
nnnnnn

1
Це досить негарно. Напевно, вас би так само добре обслужили {NAME: "Mike", AGE: 26, EVENT: 20}? Звичайно, вам все одно знадобиться, щоб ці клавіші відображалися у формі знаків відсотка у рядку введення.
davidchambers

Відповіді:


150

Вимоги оригінального запитання явно не могли б отримати вигоду від інтерполяції рядків, оскільки, схоже, це обробка під час виконання довільних ключів заміни.

Однак , якщо вам просто довелося виконати інтерполяцію рядків, ви можете використовувати:

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 .


Як допоміжна примітка, вас повинні називати replacementsа 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/…
Рафаель С

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, натомість може використовуватись %dу nodejs. З %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

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

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%
баку

3

Наразі в Javascript досі немає власного рішення для такої поведінки. Позначені шаблони щось пов’язане, але не вирішуйте.

Тут є рефактор рішення Алекса з об'єктом для заміни.

Рішення використовує функції стрілок та подібний синтаксис для заповнювачів, як власна інтерполяція 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
Дякуємо за це, чудово мати загальне рішення для рядка-заповнювача та об’єкта, який би об’єднався в нього так
Carlos P

@CarlosP, це ідея мати загальне рішення. Але я думаю, що це має бути щось рідне для мови, оскільки це звичайний випадок використання.
AMS777

2

Це дозволяє зробити саме це

NPM: 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. Використання для цього може бути, наприклад, рядками перекладу, де ви будете споживати рядок деінде і вводити туди потрібні значення.
Йоган Перссон,

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.