Форматувати рядок 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.