Yer tutucular ve ikame nesnesi kullanarak bir JavaScript dizesi biçimlendirilsin mi?


92

Şöyle bir dizem var: My Name is %NAME% and my age is %AGE%.

%XXX%yer tutuculardır. Oradaki değerleri bir nesneden değiştirmemiz gerekiyor.

Nesne şöyle görünür: {"%NAME%":"Mike","%AGE%":"26","%EVENT%":"20"}

Nesneyi ayrıştırmam ve dizeyi karşılık gelen değerlerle değiştirmem gerekiyor. Böylece nihai çıktı:

Adım Mike ve yaşım 26.

Her şey ya saf javascript ya da jquery kullanılarak yapılmalıdır.


2
Bu, bir diziden çok bir nesneye benziyor
Joel Coehoorn

3
Şimdiye kadar ne denedin? String .replace () yöntemine baktınız mı ? (Ayrıca, orada bir diziniz yok, bir nesneniz var.)
nnnnnn

1
Bu oldukça çirkin. Eminim size de aynı şekilde hizmet edersiniz {NAME: "Mike", AGE: 26, EVENT: 20}? Elbette, bu anahtarların giriş dizesinde yüzde işaretleriyle ayrılmış olarak görünmesini zorunlu kılarsınız.
davidchambers

Yanıtlar:


152

Orijinal sorunun gereksinimleri, rasgele değiştirme anahtarlarının çalışma zamanında işlenmesi gibi göründüğü için, dize enterpolasyonundan yararlanamadı.

Bununla birlikte , sadece dize enterpolasyonu yapmanız gerekiyorsa, şunu kullanabilirsiniz:

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

Dizeyi sınırlayan geri işaretlere dikkat edin, bunlar gereklidir.


Belirli OP'nin gereksinimlerine uygun bir yanıt String.prototype.replace()için, değiştirmeler için kullanabilirsiniz .

Aşağıdaki kod tüm eşleşmeleri ele alır ve değiştirilmeden dokunmaz (değiştirme değerleriniz tüm dizeler olduğu sürece, değilse aşağıya bakın).

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 .

Değiştirmelerinizden bazıları dizge değilse, önce nesnede bulunduklarından emin olun. Örneğe benzer bir formatınız varsa, yani yüzde işaretleri içine alınmışsa,in başarmak operatörü .

jsFiddle .

Bununla birlikte, biçiminizin özel bir biçimi yoksa, yani herhangi bir dizge varsa ve değiştirilen nesnenizin bir nullprototipi Object.prototype.hasOwnProperty()yoksa, değiştirilen olası alt dizelerinizin hiçbirinin prototipteki özellik adlarıyla çakışmayacağını garanti edemediğiniz sürece kullanın .

jsFiddle .

Aksi takdirde, yerine koyduğunuz dizge 'hasOwnProperty'olsaydı, sonuçta karışık bir dize alırdınız.

jsFiddle .


Bir yan not olarak, size replacementsbir Objectdeğil, bir demeniz gerekir Array.


2
+1. Güzel. Yine de davaları return replacements[all] || allörtmek isteyebilirsiniz %NotInReplacementsList%.
nnnnnn

6
Değiştirme değeri yanlışsa bu işe yaramaz. Bu yüzden bu dönüş ifadesini kullanmak daha iyidir:return all in params ? params[all] : all;
Michael Härtl

@ MichaelHärtl Sizin değiştirmelerinizin tümü dizge olmamalı mı? Boş dizeyle değiştirmek istiyorsanız, diğer yöntemlerle kontrol etmeniz daha iyi olur.
alex

1
@alex Değişimlerin tamsayı olabileceği bir durum yaşadım ve hatta 0. Bu durumda işe yaramadı.
Michael Härtl

@ MichaelHärtl Bu davayı kapsayacak şekilde güncellendi.
alex

24

ES6 şablon değişmezlerini kullanmaya ne dersiniz?

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

Şablon değişmezleri hakkında daha fazla bilgi ...


5
OP gibi yer tutuculara sahip bir nesneniz varsa, dize enterpolasyonu buna nasıl yardımcı olur?
alex

Tıkır tıkır çalışıyor! Yer tutucu problemlerime en pragmatik çözüm, mükemmel.
BAERUS

Bu çözüm, çalışma zamanı değiştirmeleri için çalışmaz
Thierry J.

13

Kolay çalışmasını sağlamak için JQuery'yi (jquery.validate.js) kullanabilirsiniz.

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

Ya da sadece bu özelliği kullanmak istiyorsanız, bu işlevi tanımlayabilir ve şu şekilde kullanabilirsiniz:

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 ekibine kredi


1
Bu eklentiyi kesinlikle sadece bunun için yüklemek istemezsiniz, ancak bunu zaten sayfadaki bir formu doğrulamak için kullanıyorum ... bu yüzden ipucu için teşekkürler!
02'de nabrown

1
Her sayı için bir normal ifade oluşturmak oldukça verimsizdir, tüm sayıları eşleştirmek ve değer dizide bulunuyorsa onu değiştirmek daha iyi olur, belki?
alex


1
+ çok güzel ... ve $.eachsizin için yapabilir, 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;}böylece sadece bunun için jquery eklemeniz gerekmez;)
Larphoid

11

Modern tarayıcıda olduğu gibi, yer tutucu, C stili işlevine benzer şekilde Chrome / Firefox'un yeni sürümü tarafından desteklenir printf().

Yer tutucular:

  • %s Dize.
  • %d, %iTam sayı.
  • %f Kayan nokta numarası.
  • %o Nesne köprüsü.

Örneğin

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

BTW, çıktıyı görmek için:

  • Chrome'da, geliştirici aracını açmak için Ctrl + Shift + Jveya kısayolu F12kullanın.
  • Firefox'ta kısayol kullanın Ctrl + Shift + KF12 geliştirici aracını açmak için veya kullanın.

@Update - nodejs desteği

Görünüşe göre nodejs desteklemiyor %f, bunun yerine %dnodejs'de kullanabilir . İle %dsayı sadece tamsayı, kayan sayı olarak basılacaktır.



5

Aşağıdaki gibi özel bir değiştirme işlevi kullanabilirsiniz:

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

Burada çalıştığını görebilirsiniz: http://jsfiddle.net/jfriend00/DyCwk/ .


1
Harika, Alex hemen hemen aynı şeyi yaptı ancak daha az kod satırında (üç terimli operatörler muhtemelen if..else'den daha yavaş olsa da).
RobG

Hey, sana +1 verdim! İkiniz de bir değiştirme işlevi yaptınız, sizinki tam olarak aynı değil ama oldukça benzer. RegExp'iniz de farklıdır, OP, ayırıcı olarak %% veya $$ veya benzer kullanılması daha iyi olacaktır - normalde bir dizede tek bir% veya% oluşması muhtemeldir, ancak iki katına çıkma olasılığı düşüktür.
RobG

4

Console.log'a daha yakın bir şey yapmak istiyorsanız, örneğin% s yer tutucularını değiştirmek gibi

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

bunu ben yazdım

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

Alacaksın

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

GÜNCELLEME

String.prototypeDize dönüşümleri ile uğraşırken faydalı olacak basit bir varyant ekledim , işte burada:

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

Bu durumda yapacaksın

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

Bu sürümü burada deneyin


2
prototipler olmadan işlevinizde bir değişiklik yaptım, formatMessage(message: string, values: string[]) { let i = 0; return message.replace(/%\w+%/g, (match, idx) => { return values[i++]; }); } bu, değerleri değiştirmek ve değiştirmek için bir mesaj alır ve arar%SOME_VALUE%
baku

4

Şu anda bu davranış için Javascript'te yerel bir çözüm yoktur. Etiketli şablonlar birbiriyle ilişkilidir, ancak çözmeyin.

Burada alex'in çözümünün değiştirmeler için bir nesne içeren bir yeniden düzenleyicisi var.

Çözüm, şablon değişmezlerinde ( yerine ) yerel Javascript enterpolasyonu gibi yer tutucular için ok işlevlerini ve benzer bir sözdizimini kullanır . Ayrıca , değiştirmelerin adlarına sınırlayıcılar ( ) eklemeye gerek yoktur .{}%%%

İki çeşni vardır: tanımlayıcı ve indirgenmiş.

Açıklayıcı çözüm:

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

Azaltılmış çözüm:

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
Bunun için teşekkürler, bir yer tutucu dizesi için genel bir çözüme ve bununla bu şekilde birleştirilecek bir nesneye sahip olmak harika
Carlos P

@CarlosP, genel bir çözüme sahip olma fikri budur. Ama bence yaygın bir kullanım durumu olduğu için bu dile özgü bir şey olmalı.
AMS777

1
Bu, aşağıdaki gibi normal ifade grupları kullanılarak biraz daha basitleştirilebilir:stringWithPlaceholders.replace(/{(\w+)}/g, (fullMatch, group1) => replacements[group1] || fullMatch )
Kade

2

Bu tam olarak bunu yapmanıza izin verir

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

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

Aşağıdakileri yaparak:

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

// My username is tjcafferkey on Git

2
Ama bunu es6'da yapabildiğinize göre bu muhtemelen biraz fazla mı?
IonicBurger

1
Bu, dizeyi tek bir yerde tek bir biçimde depolamanıza ve daha sonra tek bir işlev kullanarak karşılık gelen öğeleri daha sonra değiştirmenize olanak tanır. Bu benim bildiğim kadarıyla es6 şablon değişmezleri ile yapmak mümkün değil. Bunun bir kullanımı, örneğin dizgiyi başka bir yerde tüketeceğiniz ve istenen değerleri oraya enjekte edeceğiniz çeviri dizeleri olabilir.
Johan Persson

2

İşte bunu çalışma zamanında dinamik olarak es6 şablon değişmezlerini kullanarak yapmanın başka bir yolu.

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

Hızlı bir örnek olarak:

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

Çıktı:

jack 40 yaşında


7
Konsola kaydetmenin yanı sıra bir şey yapmak istemediğiniz sürece bu harika.
alex

13
olması gerekmiyor console.logmu?
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

Dizeyi kolayca biçimlendirmenizi sağlayan bir kod yazdım.

Bu işlevi kullanın.

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

Misal

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

Çıktı

Adım Mike ve yaşım 26

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.