Bir dizeyi şablon dizesine dönüştürme


147

Normal bir dize olarak şablon dizesi oluşturmak mümkün mü

let a="b:${b}";

sonra şablon dizesine dönüştürür

let b=10;
console.log(a.template());//b:10

olmadan eval, new Functionve dinamik kod üretimi diğer araçlar?


5
bunu başarmanın bir yolunu buldun mu? Bir gün yapmam gerekebilir ve neye vardığınızı merak ediyorum.
Bryan Rayner

@BryanRayner, js programınızın url'si config.js dosyasında "/ resources / <resource_id> / update /" dizesi olarak kalan API'dan bir veri almaya çalıştığını ve programınızdan dinamik olarak "resource_id" ifadesini koyduğunuzu varsayalım . Bu URL'yi parçalara ayırmak ve farklı alanlarda kaydetmek istemiyorsanız, bir tür dize şablonu işlemeye ihtiyacınız vardır.
Ryu_hayabusa


Eval daha iyi kullanmak yerine regex için kullanmak Eval tavsiye edilmez ve son derece cesaret kırıcı, bu yüzden lütfen onu kullanmayın developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…! b = 10 olsun; a = "b: $ {b}" olsun; yanıt ver = a.replace (/ \ $ {\ w +} /, b); conssole.log (yanıt);
Vijay Palaskar

Yanıtlar:


79

Şablon dizenizin bdeğişkene dinamik olarak (çalışma zamanında) başvurması gerektiğinden , yanıt şudur: HAYIR, dinamik kod üretmeden yapmak imkansızdır.

Ama evaloldukça basit:

let tpl = eval('`'+a+'`');

7
eval güvensiz, dinamik kod üretmenin diğer
yolları da

8
Özellikle İçin @KOLANICH durumda olduğunu - kaçış arka tırnak adize ve çok daha az güvensiz olacaktır: let tpl = eval('`'+a.replace(/`/g,'\\`')+'`');. Daha önemli olduğunu düşünüyorum evalderleyici kodunuzu optimize etmek önlemek. Ama bence bu soru ile alakasız.
alexpods

3
Aslında, şablon dizeleri içindeki işlevleri de çalıştırabilirsiniz.
KOLANICH

9
@KOLANICH Sevmediğim için üzgünüm eval. Ancak, bir şablon hazır bilgisinin kendisinin bir formu olduğunu unutmayın eval. İki örnek: var testi = Result: ${alert('hello')}; var testi = Result: ${b=4}; Her ikisi de komut dosyası bağlamında rasgele kod yürütmeye başlar. Rasgele dizelere izin vermek istiyorsanız, izin vermenin yanı sıra eval.
Manngo

6
Dikkatli ol. Babel gibi bir şey bunu aktarmayacağından, bu kod IE'de
ÇALIŞMAZ

79

Projemde ES6 ile böyle bir şey yarattım:

String.prototype.interpolate = function(params) {
  const names = Object.keys(params);
  const vals = Object.values(params);
  return new Function(...names, `return \`${this}\`;`)(...vals);
}

const template = 'Example text: ${text}';
const result = template.interpolate({
  text: 'Foo Boo'
});
console.log(result);

GÜNCELLEME Lodash bağımlılığını kaldırdım, ES6 anahtarları ve değerleri almak için eşdeğer yöntemlere sahip.


1
Merhaba, Çözümünüz harika çalışıyor, ancak React Native'da (oluşturma modu) kullandığımda bir hata atıyor: Geçersiz karakter '' ' , hata ayıklama modunda çalıştığımda çalışıyor. Görünüşe göre, babil sorunu, herhangi bir yardım?
Mohit Pandey

@MohitPandey PhantomJS altında bu kod testlerini çalıştırırken aynı hata alıyordum ve krom altında geçiyordu. Bu durumda, bence ES6 için daha iyi destek ile PhantomJS'nin yeni beta sürümü var, yüklemeyi deneyebilirsiniz.
Mateusz Moska

1
Ne yazık ki, işe yaramaz ve ben de bir regex yazdım. Cevap olarak eklendi.
Mohit Pandey

bu çözüm yalnızca şablon dizesinde "" "işaretli karakterin bulunmaması durumunda çalışır
SliverNinja - MSFT 19:17

Denediğimde anladım ReferenceError: _ is not defined. Kod ES6 değil lodashözel mi, yoksa ...?
xpt

29

Burada ne istiyorsun:

//non working code quoted from the question
let b=10;
console.log(a.template());//b:10

aşağıdakilere tam olarak eşdeğerdir (güç ve er, güvenlik açısından) eval: kod içeren bir dize alma ve bu kodu çalıştırma yeteneği; ayrıca yürütülen kodun arayan ortamındaki yerel değişkenleri görebilmesi.

JS'de bir işlevin, yerel işlev değişkenlerini, çağrısında yerel değişkenleri görmesi için bir yol yoktur eval(); Function()Yapamam bile .


JavaScript'e "şablon dizeleri" adı verilen bir şey duyduğunuzda, bıyık gibi yerleşik bir şablon kütüphanesi olduğunu varsaymak doğaldır. Öyle değil. JS için sadece dize enterpolasyonu ve çok satırlı dizeler. Bence bu bir süredir yaygın bir yanlış anlama olacak. :(


2
TBH öyle olduğunu düşündüm. Çok, çok kullanışlı olurdu.
Bryan Rayner

Bu (hala) çalışıyor mu? Ben alıyorum template is not a function.
Ionică Bizău

2
Bu cevabın üstündeki kod bloğu sorudan bir alıntıdır. İşe yaramıyor.
Jason Orendorff

27

Hayır, bunu dinamik kod oluşturma olmadan yapmanın bir yolu yoktur.

Ancak, normal bir dize, şablon dizeleri dahili olarak kullanarak bir değerler haritası ile sağlanabilecek bir işleve dönüştürecek bir işlev oluşturduk.

Şablon Dizesi Özeti Oluştur

/**
 * Produces a function which uses template strings to do simple interpolation from objects.
 * 
 * Usage:
 *    var makeMeKing = generateTemplateString('${name} is now the king of ${country}!');
 * 
 *    console.log(makeMeKing({ name: 'Bryan', country: 'Scotland'}));
 *    // Logs 'Bryan is now the king of Scotland!'
 */
var generateTemplateString = (function(){
    var cache = {};

    function generateTemplate(template){
        var fn = cache[template];

        if (!fn){
            // Replace ${expressions} (etc) with ${map.expressions}.

            var sanitized = template
                .replace(/\$\{([\s]*[^;\s\{]+[\s]*)\}/g, function(_, match){
                    return `\$\{map.${match.trim()}\}`;
                    })
                // Afterwards, replace anything that's not ${map.expressions}' (etc) with a blank string.
                .replace(/(\$\{(?!map\.)[^}]+\})/g, '');

            fn = Function('map', `return \`${sanitized}\``);
        }

        return fn;
    }

    return generateTemplate;
})();

Kullanımı:

var kingMaker = generateTemplateString('${name} is king!');

console.log(kingMaker({name: 'Bryan'}));
// Logs 'Bryan is king!' to the console.

Umarım bu birine yardımcı olur. Kodla ilgili bir sorun bulursanız, lütfen Gist'i güncelleyecek kadar nazik olun.


Teşekkürler! Javascript sprintf çözümü yerine bunu kullandım.
seangwright

1
her şablon var test = generateTemplateString('/api/${param1}/${param2}/') console.log(test({param1: 'bar', param2: 'foo'}))dönüşü için çalışmıyor/api/bar//
Guillaume Vincent

Teşekkürler, düzeltildi. Normal ifade, iki maç olması gerektiğinde tek bir $ {param1} / $ {param2} eşleşmesi içeriyordu.
Bryan Rayner

Geri keneler için destek eksik olduğu için bunun IE11'de çalışmadığını unutmayın.
s.meijer

1
Elbette, şablon dizeleri bir tarayıcı tarafından desteklenmiyorsa, bu yöntem çalışmaz. Şablon dizelerini desteklenmeyen tarayıcılarda kullanmak istiyorsanız, TypeScript gibi bir dil veya Babel gibi bir transpiler kullanmanızı öneririm; ES6'yı eski tarayıcılara aktarmanın tek yolu budur.
Bryan Rayner

9

TLDR: https://jsfiddle.net/w3jx07vt/

Herkes değişkenlere erişme konusunda endişeli görünüyor, neden sadece onları geçmiyorsunuz? Eminim arayan değişken bağlamı almak ve aşağı geçmek çok zor olmayacak. Nesneden sahne almak için bu https://stackoverflow.com/a/6394168/6563504 adresini kullanın . Şu anda sizin için test yapamıyorum, ama bu işe yarayacak.

function renderString(str,obj){
    return str.replace(/\$\{(.+?)\}/g,(match,p1)=>{return index(obj,p1)})
}

Test edilmiştir. İşte tam kod.

function index(obj,is,value) {
    if (typeof is == 'string')
        is=is.split('.');
    if (is.length==1 && value!==undefined)
        return obj[is[0]] = value;
    else if (is.length==0)
        return obj;
    else
        return index(obj[is[0]],is.slice(1), value);
}

function renderString(str,obj){
    return str.replace(/\$\{.+?\}/g,(match)=>{return index(obj,match)})
}

renderString('abc${a}asdas',{a:23,b:44}) //abc23asdas
renderString('abc${a.c}asdas',{a:{c:22,d:55},b:44}) //abc22asdas

@ s.meijer biraz ayrıntı verebilir misiniz? Bu kodu başarıyla kullanıyorum. jsfiddle.net/w3jx07vt
M3D

1
Daha iyi normal ifade ${}karakterleri seçmenize izin vermez . Deneyin:/(?!\${)([^{}]*)(?=})/g
Eric Hodonsky

@Relic jsfiddle.net/w3jx07vt/2 Bunu çalıştıramadım, yardım etmeyi umuyorum ve yazımı güncelleyeceğim? :)
M3D

Yani bu kapmak için çalışıyoruz aslında bu çok yardımcı olmaz, bunun yerine bir dize yerine yaptı. Enterpolasyon adımı eklemek yerine, string'i interp veya string olarak kullanabilirim. Fantezi değil, ama işe yaradı.
Eric Hodonsky

8

Buradaki sorun, arayanın değişkenlerine erişimi olan bir işleve sahip olmaktır. Bu yüzden doğrudan evalşablon işleme için kullanıldığını görüyoruz . Olası bir çözüm, bir sözlüğün özellikleri tarafından adlandırılan resmi parametreleri alan ve aynı sırayla karşılık gelen değerlerle çağıran bir işlev oluşturmak olabilir. Alternatif bir yol, bu kadar basit bir şeye sahip olmak olacaktır:

var name = "John Smith";
var message = "Hello, my name is ${name}";
console.log(new Function('return `' + message + '`;')());

Ve Babel derleyicisini kullanan herkes için, yaratıldığı ortamı hatırlayan bir kapak yaratmamız gerekiyor:

console.log(new Function('name', 'return `' + message + '`;')(name));

İlk snippet'iniz aslında evalsadece küresel bir namedeğişkenle çalıştığından daha kötü
Bergi

@Bergi İfadeniz geçerli - işlevin kapsamı kaybolacak. Soruna kolay bir çözüm sunmak istedim ve neler yapılabileceğine dair basitleştirilmiş bir örnek sundum. Biri sadece sorunun üstesinden gelmek için aşağıdakileri ortaya çıkarabilir: var template = function() { var name = "John Smith"; var message = "Hello, my name is ${name}"; this.local = new Function('return '+ mesaj +';')();}
didinko

Hayır, tam olarak o olur Ne değil iş - new Functionerişimi yok var nameiçinde templateişlevi.
Bergi

İkinci pasaj sorunumu düzeltti ... Benden oy verin! Teşekkürler, bu bir iframe dinamik yönlendirme ile yaşadığımız geçici bir sorunu çözmeye yardımcı oldu :)
Kris Boyd

7

Burada yayınlanan birçok iyi çözüm var, ancak henüz ES6 String.raw yöntemini kullanan yok . İşte benim çelişki. Yalnızca nesneden geçirilen özellikleri kabul etmesi bakımından önemli bir sınırlama vardır, yani şablonda kod yürütme çalışmaz.

function parseStringTemplate(str, obj) {
    let parts = str.split(/\$\{(?!\d)[\wæøåÆØÅ]*\}/);
    let args = str.match(/[^{\}]+(?=})/g) || [];
    let parameters = args.map(argument => obj[argument] || (obj[argument] === undefined ? "" : obj[argument]));
    return String.raw({ raw: parts }, ...parameters);
}
let template = "Hello, ${name}! Are you ${age} years old?";
let values = { name: "John Doe", age: 18 };

parseStringTemplate(template, values);
// output: Hello, John Doe! Are you 18 years old?
  1. Dizeyi bağımsız değişken olmayan metin parçalarına ayırın. Bkz. Normal ifade .
    parts: ["Hello, ", "! Are you ", " years old?"]
  2. Dizeyi özellik adlarına ayırın. Eşleşme başarısız olursa dizi boş.
    args: ["name", "age"]
  3. objÖzellik adına göre parametreleri eşleyin. Çözüm, sığ bir seviye haritalama ile sınırlıdır. Tanımsız değerler boş bir dize ile değiştirilir, ancak diğer sahte değerler kabul edilir.
    parameters: ["John Doe", 18]
  4. Sonucu kullanın String.raw(...)ve döndürün .

Merak ettiğimizde, String.raw aslında burada hangi değeri sağlıyor? Dizeyi ayrıştırma ve alt bölümlerin ne olduğunu takip etme işini yaptığınız anlaşılıyor. Bu sadece .replace()tekrar tekrar aramaktan çok mu farklı ?
Steve Bennett

Adil nokta, @SteveBennett. Normal bir dizgiyi bir şablon dizgeye çevirirken bazı problemler yaşadım ve ham nesneyi kendim oluşturarak bir çözüm buldum. Sanırım String.raw bir birleştirme yöntemini azaltır, ama oldukça iyi çalıştığını düşünüyorum. Bununla birlikte güzel bir çözüm görmek istiyorum .replace():) Bence okunabilirlik önemlidir, bu yüzden düzenli ifadeleri kendim kullanırken, hepsini anlamaya yardımcı olmak için onları adlandırmaya çalışıyorum ...
pekaaw

6

Daniel'in cevabına benzer (ve s.meijer'in özü ) ama daha okunabilir:

const regex = /\${[^{]+}/g;

export default function interpolate(template, variables, fallback) {
    return template.replace(regex, (match) => {
        const path = match.slice(2, -1).trim();
        return getObjPath(path, variables, fallback);
    });
}

//get the specified property or nested property of an object
function getObjPath(path, obj, fallback = '') {
    return path.split('.').reduce((res, key) => res[key] || fallback, obj);
}

Not: Bu, s.meijer'in orijinalini biraz geliştirir, çünkü bu gibi şeylerle eşleşmez ${foo{bar}(normal ifade sadece iç ${ve olmayan kıvırcık olmayan karakterlere izin verir }).


GÜNCELLEME: Bunu kullanarak bir örnek istendi, işte burada:

const replacements = {
    name: 'Bob',
    age: 37
}

interpolate('My name is ${name}, and I am ${age}.', replacements)

Bunu kullanarak bir örnek gönderebilir misiniz? Bu javascript benim biraz ötesinde. /\$\{(.*?)(?!\$\{)\}/g(Yuva kıvırcık parantez işlemek için) bir regex öneririm . Çalışan bir çözümüm var ama sizinki kadar taşınabilir olduğundan emin değilim, bu yüzden bunun bir sayfada nasıl uygulanması gerektiğini görmek isterim. Benimki de kullanır eval().
Düzenli Joe

Ben de devam ettim ve bir cevap da gönderdim ve bunu nasıl daha güvenli ve performans odaklı hale getireceğinizle ilgili görüşlerinizi almak isterim: stackoverflow.com/a/48294208 .
Düzenli Joe

@RegularJoe Bir örnek ekledim. Amacım basit tutmaktı, ancak iç içe kıvırcık parantezlerle uğraşmak istiyorsanız, normal ifadeyi değiştirmeniz gerektiği konusunda haklısınız. Ancak, normal bir dizeyi bir şablon değişmezmiş gibi (bu işlevin tüm amacı) değerlendirirken bunun için bir kullanım örneği düşünemiyorum. Aklında ne var?
Matt Browne

Ayrıca ne performans uzmanı ne de güvenlik uzmanıyım; cevabım gerçekten sadece önceki iki cevabı birleştirmek. Ancak, kullanmanın evalgüvenlik sorunlarına neden olabilecek olası hatalara çok daha açık kaldığını söyleyeceğim , oysa tüm sürümümün güvenli olması gereken noktadan ayrılmış bir yoldan bir nesne üzerindeki bir özelliği aramak olduğu.
Matt Browne

5

Dize prototipini kullanabilirsiniz, örneğin

String.prototype.toTemplate=function(){
    return eval('`'+this+'`');
}
//...
var a="b:${b}";
var b=10;
console.log(a.toTemplate());//b:10

Ama asıl sorunun cevabı bir yolu yok.


5

Ben s.meijer'in cevabını beğendim ve kendi versiyonunu ona dayanarak yazdım:

function parseTemplate(template, map, fallback) {
    return template.replace(/\$\{[^}]+\}/g, (match) => 
        match
            .slice(2, -1)
            .trim()
            .split(".")
            .reduce(
                (searchObject, key) => searchObject[key] || fallback || match,
                map
            )
    );
}

1
Temiz! Gerçekten Temiz!
xpt

4

Bu yöntemi Internet Explorer desteğiyle istedim. Arka kenelerin IE11 tarafından bile desteklenmediği ortaya çıktı. Ayrıca; kullanmak evalya da eşdeğeri Functiondoğru hissetmiyor.

Dikkat çeken biri için; Ben de ters çentikler kullanıyorum, ama bunlar babil gibi derleyiciler tarafından kaldırılıyor. Başkaları tarafından önerilen yöntemler, çalışma zamanına bağlıdır. Daha önce de belirtildiği gibi; Bu IE11 ve daha düşük bir sorundur.

Ben de bu yüzden geldim:

function get(path, obj, fb = `$\{${path}}`) {
  return path.split('.').reduce((res, key) => res[key] || fb, obj);
}

function parseTpl(template, map, fallback) {
  return template.replace(/\$\{.+?}/g, (match) => {
    const path = match.substr(2, match.length - 3).trim();
    return get(path, map, fallback);
  });
}

Örnek çıktı:

const data = { person: { name: 'John', age: 18 } };

parseTpl('Hi ${person.name} (${person.age})', data);
// output: Hi John (18)

parseTpl('Hello ${person.name} from ${person.city}', data);
// output: Hello John from ${person.city}

parseTpl('Hello ${person.name} from ${person.city}', data, '-');
// output: Hello John from -

"eval veya eşdeğerini kullanmak Function doğru hissetmez." ... Evet ... Katılıyorum, ama bence bu "mmhkay, kullanalım" diyebilen az sayıdaki kullanım durumlarından biri. Lütfen jsperf.com/es6-string-tmpl adresini kontrol edin - bu benim pratik kullanım durumum. İşlevinizi (benimkiyle aynı normal ifade ile) ve benimkini (eval + string literals) kullanma. Teşekkürler! :)
Andrea Puddu

@AndreaPuddu, performansınız gerçekten daha iyi. Ama sonra tekrar; IE'de şablon dizeler desteklenmez. Yani eval('`' + taggedURL + '`')işe yaramıyor.
s.meijer

"Görünüşe göre" daha iyi söyleyebilirim, çünkü tek başına test edildi ... Bu testin tek amacı potansiyel performans sorunlarını görmekti eval. Şablon değişmezleriyle ilgili olarak: bunu tekrar belirttiğiniz için teşekkürler. Kodumu aktarmak için Babel kullanıyorum ama fonksiyonum hala görünüşte işe yaramayacak 😐
Andrea Puddu

3

Şu anda mevcut cevaplar hakkında yorum yapamıyorum, bu yüzden Bryan Raynor'ın mükemmel yanıtı hakkında doğrudan yorum yapamıyorum. Böylece, bu cevap cevabını hafif bir düzeltme ile güncelleyecektir.

Kısacası, işlevi oluşturulan işlevi gerçekten önbelleğe almaz, bu nedenle daha önce şablonu görüp görmediğine bakılmaksızın her zaman yeniden oluşturur. Düzeltilmiş kod:

    /**
     * Produces a function which uses template strings to do simple interpolation from objects.
     * 
     * Usage:
     *    var makeMeKing = generateTemplateString('${name} is now the king of ${country}!');
     * 
     *    console.log(makeMeKing({ name: 'Bryan', country: 'Scotland'}));
     *    // Logs 'Bryan is now the king of Scotland!'
     */
    var generateTemplateString = (function(){
        var cache = {};

        function generateTemplate(template){
            var fn = cache[template];

            if (!fn){
                // Replace ${expressions} (etc) with ${map.expressions}.

                var sanitized = template
                    .replace(/\$\{([\s]*[^;\s\{]+[\s]*)\}/g, function(_, match){
                        return `\$\{map.${match.trim()}\}`;
                    })
                    // Afterwards, replace anything that's not ${map.expressions}' (etc) with a blank string.
                    .replace(/(\$\{(?!map\.)[^}]+\})/g, '');

                fn = cache[template] = Function('map', `return \`${sanitized}\``);
            }

            return fn;
        };

        return generateTemplate;
    })();

3

@Mateusz Moska, çözüm harika çalışıyor, ancak React Native'da (yapı modu) kullandığımda bir hata atıyor: Geçersiz karakter '' ' , hata ayıklama modunda çalıştırdığımda çalışıyor.

Bu yüzden regex kullanarak kendi çözümümü yazdım.

String.prototype.interpolate = function(params) {
  let template = this
  for (let key in params) {
    template = template.replace(new RegExp('\\$\\{' + key + '\\}', 'g'), params[key])
  }
  return template
}

const template = 'Example text: ${text}',
  result = template.interpolate({
    text: 'Foo Boo'
  })

console.log(result)

Demo: https://es6console.com/j31pqx1p/

NOT: Bir sorunun temel nedenini bilmediğim için, bir kez yanıt verebilmeleri için tepki yerel repo, https://github.com/facebook/react-native/issues/14107 bir bilet yükseltti düzeltmek / aynı konuda bana rehberlik :)


bu, geri işaretli karakteri içeren şablonları desteklemez. Bununla birlikte, cazip bir desen icat etmek yerine, muhtemelen sadece bıyık veya benzeri kullanarak daha iyi durumdasınız . şablonlarınızın ne kadar karmaşık olduğuna bağlı olarak bu, uç durumları dikkate almayan kaba kuvvet yaklaşımıdır - anahtar özel bir normal ifade deseni içerebilir.
SliverNinja - MSFT

2

Hala dinamik ama çıplak bir eval kullanmaktan daha kontrollü görünüyor:

const vm = require('vm')
const moment = require('moment')


let template = '### ${context.hours_worked[0].value} \n Hours worked \n #### ${Math.abs(context.hours_worked_avg_diff[0].value)}% ${fns.gt0(context.hours_worked_avg_diff[0].value, "more", "less")} than usual on ${fns.getDOW(new Date())}'
let context = {
  hours_worked:[{value:10}],
  hours_worked_avg_diff:[{value:10}],

}


function getDOW(now) {
  return moment(now).locale('es').format('dddd')
}

function gt0(_in, tVal, fVal) {
  return _in >0 ? tVal: fVal
}



function templateIt(context, template) {
  const script = new vm.Script('`'+template+'`')
  return script.runInNewContext({context, fns:{getDOW, gt0 }})
}

console.log(templateIt(context, template))

https://repl.it/IdVt/3


1

Bu çözüm ES6 olmadan çalışır:

function render(template, opts) {
  return new Function(
    'return new Function (' + Object.keys(opts).reduce((args, arg) => args += '\'' + arg + '\',', '') + '\'return `' + template.replace(/(^|[^\\])'/g, '$1\\\'') + '`;\'' +
    ').apply(null, ' + JSON.stringify(Object.keys(opts).reduce((vals, key) => vals.push(opts[key]) && vals, [])) + ');'
  )();
}

render("hello ${ name }", {name:'mo'}); // "hello mo"

Not: Functionyapıcı her zaman global kapsamda oluşturulur, bu da global değişkenlerin şablon tarafından üzerine yazılmasına neden olabilir, örn.render("hello ${ someGlobalVar = 'some new value' }", {name:'mo'});


0

Javascript'te hoş bir özellik olacak bir şey üzerinde tekerleği yeniden icat ettiğimiz için.

eval()Güvenli değil, kullanıyorum , javascript güvenli değil. Javascript ile mükemmel olmadığımı kolayca itiraf ediyorum, ancak bir ihtiyacım vardı ve bir cevaba ihtiyacım vardı, bu yüzden bir tane yaptım.

Bir ile benim değişkenleri stilize seçti @ziyade bir daha $ben hazır bilgilerinin satırlı özelliği kullanmak istiyorsanız, özellikle çünkü olmadan şey hazır til değerlendirilmesi. Yani değişken sözdizimi@{OptionalObject.OptionalObjectN.VARIABLE_NAME}

Ben hiçbir javascript uzmanı, bu yüzden memnuniyetle iyileştirme hakkında tavsiye almak istiyorum ama ...

var prsLiteral, prsRegex = /\@\{(.*?)(?!\@\{)\}/g
for(i = 0; i < myResultSet.length; i++) {
    prsLiteral = rt.replace(prsRegex,function (match,varname) {
        return eval(varname + "[" + i + "]");
        // you could instead use return eval(varname) if you're not looping.
    })
    console.log(prsLiteral);
}

Bunu çok basit bir uygulama takip ediyor

myResultSet = {totalrecords: 2,
Name: ["Bob", "Stephanie"],
Age: [37,22]};

rt = `My name is @{myResultSet.Name}, and I am @{myResultSet.Age}.`

var prsLiteral, prsRegex = /\@\{(.*?)(?!\@\{)\}/g
for(i = 0; i < myResultSet.totalrecords; i++) {
    prsLiteral = rt.replace(prsRegex,function (match,varname) {
        return eval(varname + "[" + i + "]");
        // you could instead use return eval(varname) if you're not looping.
    })
    console.log(prsLiteral);
}

Gerçek uygulamamda kullanmayı seçiyorum @{{variable}} . Bir set daha diş teli. Saçma sapan bu beklenmedik bir şekilde karşılaşmak. Bunun için normal ifade şöyle görünür/\@\{\{(.*?)(?!\@\{\{)\}\}/g

Bunu okumayı kolaylaştırmak için

\@\{\{    # opening sequence, @{{ literally.
(.*?)     # capturing the variable name
          # ^ captures only until it reaches the closing sequence
(?!       # negative lookahead, making sure the following
          # ^ pattern is not found ahead of the current character
  \@\{\{  # same as opening sequence, if you change that, change this
)
\}\}      # closing sequence.

Eğer regex deneyimli değilseniz, oldukça güvenli bir kural her alfanümerik olmayan karakter kaçmak ve yok hiç birçok kaçan harfler regex hemen hemen tüm lezzetleri için özel anlama sahip olarak gereksiz harfleri kaçmak.


0

Andrea Giammarchi'nin bu küçük JS modülünü github'dan denemelisiniz: https://github.com/WebReflection/backtick-template

/*! (C) 2017 Andrea Giammarchi - MIT Style License */
function template(fn, $str, $object) {'use strict';
  var
    stringify = JSON.stringify,
    hasTransformer = typeof fn === 'function',
    str = hasTransformer ? $str : fn,
    object = hasTransformer ? $object : $str,
    i = 0, length = str.length,
    strings = i < length ? [] : ['""'],
    values = hasTransformer ? [] : strings,
    open, close, counter
  ;
  while (i < length) {
    open = str.indexOf('${', i);
    if (-1 < open) {
      strings.push(stringify(str.slice(i, open)));
      open += 2;
      close = open;
      counter = 1;
      while (close < length) {
        switch (str.charAt(close++)) {
          case '}': counter -= 1; break;
          case '{': counter += 1; break;
        }
        if (counter < 1) {
          values.push('(' + str.slice(open, close - 1) + ')');
          break;
        }
      }
      i = close;
    } else {
      strings.push(stringify(str.slice(i)));
      i = length;
    }
  }
  if (hasTransformer) {
    str = 'function' + (Math.random() * 1e5 | 0);
    if (strings.length === values.length) strings.push('""');
    strings = [
      str,
      'with(this)return ' + str + '([' + strings + ']' + (
        values.length ? (',' + values.join(',')) : ''
      ) + ')'
    ];
  } else {
    strings = ['with(this)return ' + strings.join('+')];
  }
  return Function.apply(null, strings).apply(
    object,
    hasTransformer ? [fn] : []
  );
}

template.asMethod = function (fn, object) {'use strict';
  return typeof fn === 'function' ?
    template(fn, this, object) :
    template(this, fn);
};

Demo (aşağıdaki testlerin tümü doğrudur):

const info = 'template';
// just string
`some ${info}` === template('some ${info}', {info});

// passing through a transformer
transform `some ${info}` === template(transform, 'some ${info}', {info});

// using it as String method
String.prototype.template = template.asMethod;

`some ${info}` === 'some ${info}'.template({info});

transform `some ${info}` === 'some ${info}'.template(transform, {info});

0

İşlev olarak bir açıklama ile bir tür yaparak kendi çözümümü yaptım

export class Foo {
...
description?: Object;
...
}

let myFoo:Foo = {
...
  description: (a,b) => `Welcome ${a}, glad to see you like the ${b} section`.
...
}

ve böylece:

let myDescription = myFoo.description('Bar', 'bar');

0

Eval daha iyi kullanmak yerine regex için kullanın

Eval tavsiye edilmez ve son derece cesaret kırıcı, bu yüzden lütfen kullanmayın ( mdn eval ).

 let b = 10;
 let a="b:${b}";

let response = a.replace(/\${\w+}/ ,b);
conssole.log(response);

biri için çalışır, "a $ {a}, b {b} ..." varsa ne olur?
leachim
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.