Memformat string JavaScript menggunakan placeholder dan objek substitusi?

92

Saya memiliki string dengan mengatakan: My Name is %NAME% and my age is %AGE%.

%XXX%adalah placeholder. Kita perlu mengganti nilai di sana dari suatu objek.

Objek terlihat seperti: {"%NAME%":"Mike","%AGE%":"26","%EVENT%":"20"}

Saya perlu mengurai objek dan mengganti string dengan nilai yang sesuai. Sehingga hasil akhirnya adalah:

Nama saya Mike dan umur saya 26 tahun.

Semuanya harus dilakukan baik menggunakan javascript atau jquery murni.

Joby Joseph
sumber
2
Itu lebih terlihat seperti sebuah objek daripada sebuah array
Joel Coehoorn
3
Apa yang sudah kamu coba sejauh ini? Pernahkah Anda melihat metode string .replace () ? (Juga, Anda tidak memiliki larik di sana, Anda memiliki objek.)
nnnnnn
1
Itu sangat jelek. Tentunya Anda akan dilayani dengan baik {NAME: "Mike", AGE: 26, EVENT: 20}? Anda masih membutuhkan kunci-kunci ini agar muncul diurutkan berdasarkan tanda persen dalam string input, tentunya.
davidchambers

Jawaban:

152

Persyaratan dari pertanyaan asli jelas tidak bisa mendapatkan keuntungan dari interpolasi string, karena sepertinya ini adalah pemrosesan waktu proses dari kunci pengganti yang berubah-ubah.

Namun , jika Anda baru saja melakukan interpolasi string, Anda dapat menggunakan:

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

Perhatikan backticks yang membatasi string, itu diperlukan.


Untuk jawaban yang sesuai dengan kebutuhan OP tertentu, Anda dapat menggunakan String.prototype.replace()untuk penggantian.

Kode berikut akan menangani semua kecocokan dan tidak menyentuh yang tanpa penggantinya (selama nilai penggantinya adalah semua string, jika tidak, lihat di bawah).

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 .

Jika beberapa pengganti Anda bukan string, pastikan mereka ada di objek terlebih dahulu. Jika Anda memiliki format seperti contoh, yaitu dibungkus dalam tanda persentase, Anda dapat menggunakan inoperator untuk melakukannya.

jsFiddle .

Namun, jika format Anda tidak memiliki format khusus, misalnya string apa pun, dan objek pengganti Anda tidak memiliki nullprototipe, gunakan Object.prototype.hasOwnProperty(), kecuali Anda dapat menjamin bahwa tidak ada substring yang mungkin diganti yang akan bentrok dengan nama properti pada prototipe.

jsFiddle .

Jika tidak, jika string pengganti Anda adalah 'hasOwnProperty', Anda akan mendapatkan string yang kacau balau.

jsFiddle .


Sebagai catatan tambahan, Anda harus disebut replacementsan Object, bukan Array.

alex
sumber
2
+1. Bagus. Meskipun Anda mungkin ingin mengatakan return replacements[all] || alluntuk menutupi %NotInReplacementsList%kasus.
nnnnnn
6
Ini tidak akan berfungsi jika nilai penggantinya salah. Jadi lebih baik menggunakan pernyataan pengembalian ini:return all in params ? params[all] : all;
Michael Härtl
@ MichaelHärtl Bukankah semua pengganti Anda harus string? Jika ingin mengganti dengan string kosong, lebih baik dicek dengan cara lain.
alex
1
@alex Saya memiliki situasi di mana penggantian juga bisa berupa bilangan bulat, dan bahkan 0. Dalam hal ini tidak berhasil.
Michael Härtl
@ MichaelHärtl Diperbarui untuk menutupi kasus itu.
alex
24

Bagaimana kalau menggunakan literal template ES6?

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

Lebih lanjut tentang literal template ...

Tomasz Mularczyk
sumber
5
Jika Anda memiliki objek dengan placeholder seperti OP, bagaimana interpolasi string membantu itu?
alex
Bekerja seperti pesona! Solusi paling pragmatis untuk masalah penempatan saya, sempurna.
BAERUS
Solusi ini tidak berfungsi untuk penggantian runtime
Thierry J.
13

Anda dapat menggunakan JQuery (jquery.validate.js) untuk membuatnya bekerja dengan mudah.

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

Atau jika Anda ingin menggunakan fitur itu saja, Anda dapat menentukan fungsi itu dan menggunakannya sesuka hati

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"]));

kredit untuk tim jquery.validate.js

zawhtut.dll
sumber
1
Anda pasti tidak ingin memuat plugin ini hanya untuk ini, tetapi saya sudah menggunakan ini untuk memvalidasi formulir di halaman ... jadi terima kasih atas tipnya!
muncul
1
Cukup tidak efisien untuk membuat regex untuk setiap angka, akan lebih baik untuk mencocokkan semua angka dan kemudian mengganti jika nilainya ditemukan dalam array, mungkin?
alex
bagi mereka yang tertarik, itu terjadi di sini: github.com/jquery-validation/jquery-validation/blob/master/src/…
Raphael C
1
+ sangat bagus ... dan untuk $.eachAnda bisa membuatnya 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;}sehingga Anda tidak perlu memasukkan jquery hanya untuk yang satu itu;)
Larphoid
11

Seperti peramban modern, placeholder didukung oleh versi baru dari Chrome / Firefox, sama seperti fungsi C gaya printf().

Placeholder:

  • %s Tali.
  • %d, %iBilangan bulat.
  • %f Angka floating point.
  • %o Hyperlink objek.

misalnya

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

BTW, untuk melihat hasilnya:

  • Di Chrome, gunakan pintasan Ctrl + Shift + Jatau F12untuk membuka alat pengembang.
  • Di Firefox, gunakan pintasan Ctrl + Shift + Katau F12untuk membuka alat pengembang.

@Update - dukungan nodejs

Sepertinya nodejs tidak mendukung %f, sebaliknya, bisa digunakan %ddi nodejs. Dengan %dangka akan dicetak sebagai angka mengambang, bukan hanya bilangan bulat.

Eric Wang
sumber
6

Gunakan saja 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%"]);
hafichuk
sumber
3
wajib "silakan gunakan MDN sebagai referensi": developer.mozilla.org/en/JavaScript/Reference/Global_Objects/…
mu terlalu pendek
2
Terima kasih untuk orang-orang yang memukul - dihargai;)
hafichuk
5

Anda dapat menggunakan fungsi ganti kustom seperti ini:

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

Anda dapat melihatnya bekerja di sini: http://jsfiddle.net/jfriend00/DyCwk/ .

jfriend00
sumber
1
Keren, Alex melakukan hal yang persis sama tetapi dalam baris kode yang lebih sedikit (meskipun operator terner kemungkinan lebih lambat daripada if..else).
RobG
Hai, saya memberi Anda +1! Anda berdua melakukan fungsi replace, milik Anda tidak persis sama tetapi sangat mirip. RegExp Anda juga berbeda, OP akan lebih baik menggunakan %% atau $$ atau serupa dengan pembatas - satu% atau% kemungkinan besar terjadi dalam string secara normal, tetapi kemungkinan besar tidak akan berlipat ganda.
RobG
4

Jika Anda ingin melakukan sesuatu yang lebih dekat ke console.log seperti mengganti% s placeholder seperti di

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

Saya menulis ini

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

kamu akan mendapatkan

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

MEMPERBARUI

Saya telah menambahkan varian sederhana yang String.prototypeberguna saat berhadapan dengan transformasi string, ini dia:

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

Dalam hal ini Anda akan melakukannya

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

Coba versi ini di sini

loretoparisi
sumber
2
Saya membuat variasi pada fungsi Anda tanpa prototipe. formatMessage(message: string, values: string[]) { let i = 0; return message.replace(/%\w+%/g, (match, idx) => { return values[i++]; }); } Ini membutuhkan pesan ke format dan susunan nilai pengganti dan mencari%SOME_VALUE%
baku
4

Saat ini masih belum ada solusi asli di Javascript untuk perilaku ini. Templat yang diberi tag adalah sesuatu yang terkait, tetapi tidak menyelesaikannya.

Di sini ada refaktor solusi alex dengan objek untuk penggantian.

Solusinya menggunakan fungsi panah dan sintaks yang serupa untuk placeholder sebagai interpolasi Javascript asli dalam literal template ( {}bukan %%). Juga tidak perlu menyertakan pembatas ( %) di nama pengganti.

Ada dua rasa: deskriptif dan direduksi.

Solusi deskriptif:

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

Solusi yang dikurangi:

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

AMS777
sumber
1
Terima kasih untuk ini, sangat bagus memiliki solusi umum untuk string placeholder dan objek untuk digabungkan ke dalamnya seperti ini
Carlos P
@CarlosP, itulah idenya, untuk memiliki solusi umum. Tapi saya pikir itu harus sesuatu yang asli dari bahasa tersebut, karena itu kasus penggunaan umum.
AMS777
1
Ini dapat lebih disederhanakan dengan menggunakan grup regex seperti ini:stringWithPlaceholders.replace(/{(\w+)}/g, (fullMatch, group1) => replacements[group1] || fullMatch )
Kade
2

Ini memungkinkan Anda melakukan hal itu

NPM: https://www.npmjs.com/package/stringinject

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

Dengan melakukan hal berikut:

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

// My username is tjcafferkey on Git
tjcafferkey.dll
sumber
2
Tapi karena Anda bisa melakukannya di es6, itu mungkin sedikit berlebihan?
IonicBurger
1
Ini memungkinkan Anda menyimpan string di satu tempat dalam satu format dan kemudian di lain waktu mengganti item yang sesuai dengan hanya menggunakan satu fungsi. Itu menurut pengetahuan saya tidak mungkin dilakukan dengan literal template es6. Penggunaan untuk ini misalnya akan menjadi string terjemahan di mana Anda akan menggunakan string di tempat lain dan memasukkan nilai yang diinginkan di sana.
Johan Persson
2

Berikut adalah cara lain untuk melakukan ini dengan menggunakan literal template es6 secara dinamis saat runtime.

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

Simon Schärer
sumber
1

Sebagai contoh cepat:

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

Outputnya adalah:

jack berusia 40 tahun

Yomi
sumber
7
Itu bagus, kecuali jika Anda ingin melakukan sesuatu selain memasukkannya ke konsol.
alex
13
bukankah seharusnya begitu 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?"
Shubham Vyas
sumber
0

Saya telah menulis kode yang memungkinkan Anda memformat string dengan mudah.

Gunakan fungsi ini.

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

Contoh

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

Keluaran

Nama saya Mike dan umur saya 26 tahun

bikram
sumber