Converti una stringa in una stringa modello


147

È possibile creare una stringa modello come una normale stringa

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

e quindi convertirlo in una stringa di modello

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

colpo eval, new Functioned altri mezzi di generazione di codice dinamico?


5
hai trovato un modo per raggiungere questo obiettivo? Potrei aver bisogno di farlo un giorno e sono curioso di sapere a cosa sei arrivato.
Bryan Rayner,

@BryanRayner dice che il tuo programma js sta cercando di recuperare un dato dall'API di riposo, il cui url si trova in un file config.js come una stringa "/ resources / <resource_id> / update /" e metti "resource_id" dinamicamente dal tuo programma . A meno che non si desideri dividere l'URL in parti e salvarlo in diverse aree, è necessaria una sorta di elaborazione del modello di stringa.
Ryu_hayabusa,


Invece di usare eval meglio è usare regex Eval non è raccomandato e altamente sconsigliato, quindi per favore non usarlo developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…! let b = 10; lascia a = "b: $ {b}"; let response = a.replace (/ \ $ {\ w +} /, b); conssole.log (risposta);
Vijay Palaskar,

Risposte:


79

Poiché la stringa del modello deve ottenere un riferimento bdinamico alla variabile (in runtime), la risposta è: NO, è impossibile fare a meno della generazione dinamica del codice.

Ma con evalè abbastanza semplice:

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

7
eval è insicuro, così come altri mezzi per la generazione di codice dinamico
KOLANICH

8
@KOLANICH Per particolari quel caso - le citazioni scappare e ritornare in acorda e sarà molto meno insicuro: let tpl = eval('`'+a.replace(/`/g,'\\`')+'`');. Penso che sia più importante evalimpedire che il compilatore ottimizzi il tuo codice. Ma penso che sia irrilevante per questa domanda.
alexpods

3
In effetti, puoi anche eseguire funzioni all'interno delle stringhe del modello.
KOLANICH,

9
@KOLANICH Mi dispiace non ti piace eval. Tuttavia, ricorda che un modello letterale è esso stesso una forma di eval. Due esempi: var test = Result: ${alert('hello')}; var test = Result: ${b=4}; Entrambi finiranno per eseguire codice arbitrario nel contesto dello script. Se si desidera consentire stringhe arbitrarie, è possibile che sia consentito eval.
Manngo,

6
Stai attento. Dato che qualcosa come Babel non lo trasporrà, questo codice NON funzionerà in IE
cgsd

79

Nel mio progetto ho creato qualcosa del genere con ES6:

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

AGGIORNAMENTO Ho rimosso la dipendenza da lodash, ES6 ha metodi equivalenti per ottenere chiavi e valori.


1
Ciao, la tua soluzione funziona alla grande, ma quando l'ho usata in React Native (modalità build), genera un errore: carattere non valido '' ' , sebbene funzioni quando corro in modalità debug. Sembra, problema babele, qualche aiuto?
Mohit Pandey,

@MohitPandey Stavo ottenendo lo stesso errore quando stavo eseguendo i test di questo codice sotto PhantomJS e stava passando sotto Chrome. In tal caso, penso che ci sia una nuova versione beta di PhantomJS in arrivo con un miglior supporto per ES6, puoi provare a installarlo.
Mateusz Moska,

1
Sfortunatamente, non funziona e ho scritto una regex per lo stesso. Aggiunto anche come risposta.
Mohit Pandey,

questa soluzione funziona solo se il carattere "` "con segno di spunta non è presente nella stringa del modello
SliverNinja - MSFT

Quando l'ho provato ho avuto ReferenceError: _ is not defined. È un codice non ES6 ma lodashspecifico o ...?
xpt,

29

Cosa stai chiedendo qui:

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

è esattamente equivalente (in termini di potenza e, er, sicurezza) a eval: la capacità di prendere una stringa contenente codice ed eseguirlo; e anche la possibilità per il codice eseguito di vedere le variabili locali nell'ambiente del chiamante.

In JS non è possibile che una funzione veda le variabili locali nel suo chiamante, a meno che tale funzione non lo sia eval(). Neanche ci Function()riesco.


Quando senti qualcosa chiamato "stringhe di modelli" in arrivo su JavaScript, è naturale supporre che sia una libreria di modelli integrata, come Moustache. Non lo è. È principalmente solo interpolazione di stringhe e stringhe multilinea per JS. Penso che questo sarà un malinteso comune per un po ', però. :(


2
TBH è quello che pensavo fosse. Sarebbe stato molto, molto utile.
Bryan Rayner,

Funziona (ancora)? Sto ottenendo template is not a function.
Ionică Bizău,

2
Il blocco di codice nella parte superiore di questa risposta è una citazione dalla domanda. Non funziona.
Jason Orendorff il

27

No, non esiste un modo per farlo senza la generazione di codice dinamico.

Tuttavia, ho creato una funzione che trasformerà una stringa normale in una funzione che può essere fornita con una mappa di valori, usando internamente stringhe di template.

Genera sintesi stringa modello

/**
 * 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;
})();

Uso:

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

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

Spero che questo aiuti qualcuno. Se riscontri un problema con il codice, si prega di essere così gentile da aggiornare Gist.


Grazie! Ho usato questo invece di una soluzione sprintf javascript.
seangwright,

1
non funziona per ogni var test = generateTemplateString('/api/${param1}/${param2}/') console.log(test({param1: 'bar', param2: 'foo'}))ritorno dei modelli/api/bar//
Guillaume Vincent,

Grazie, risolto. La regex includeva una singola partita di $ {param1} / $ {param2} quando avrebbe dovuto essere due partite.
Bryan Rayner,

Si noti che questo non funziona in IE11, a causa della mancanza di supporto per le zecche posteriori.
s.meijer,

1
Naturalmente, se le stringhe di modello non sono supportate da un browser, questo metodo non funzionerà. Se vuoi usare stringhe di template in browser non supportati, ti consiglio di usare un linguaggio come TypeScript o un transpiler come Babel; Questo è l'unico modo per inserire ES6 nei vecchi browser.
Bryan Rayner,

9

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

Tutti sembrano preoccupati dell'accesso alle variabili, perché non passarle e basta? Sono sicuro che non sarà troppo difficile ottenere il contesto variabile nel chiamante e trasmetterlo. Usa questo https://stackoverflow.com/a/6394168/6563504 per ottenere oggetti di scena da obj. Non posso testare per te adesso, ma dovrebbe funzionare.

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

Provato. Ecco il codice completo.

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 potresti elaborare? Sto usando questo codice con successo. jsfiddle.net/w3jx07vt
M3D

1
Una regex migliore ti permetterebbe di non selezionare i ${}personaggi. Prova:/(?!\${)([^{}]*)(?=})/g
Eric Hodonsky,

@Relic jsfiddle.net/w3jx07vt/2 Non riuscivo a farlo funzionare, ti va di dare una mano e aggiornerò il mio post? :)
M3D,

Quindi il modo in cui stai cercando di afferrarlo non aiuta molto, ho finito invece per sostituire una stringa. Invece di aggiungere un passaggio di interpolazione, posso usare la stringa come interp o stringa. Non è lussuoso, ma ha funzionato.
Eric Hodonsky,

8

Il problema qui è avere una funzione che ha accesso alle variabili del suo chiamante. Questo è il motivo per cui vediamo l' evalutilizzo diretto per l'elaborazione dei modelli. Una possibile soluzione sarebbe quella di generare una funzione prendendo parametri formali nominati dalle proprietà di un dizionario e chiamandola con i valori corrispondenti nello stesso ordine. Un modo alternativo sarebbe quello di avere qualcosa di semplice come questo:

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

E per chiunque utilizzi il compilatore Babel dobbiamo creare una chiusura che ricordi l'ambiente in cui è stata creata:

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

Il tuo primo frammento in realtà è peggio che evalperché funziona solo con una namevariabile globale
Bergi,

@Bergi L'affermazione è valida: l'ambito della funzione andrà perso. Volevo presentare una soluzione semplice al problema e ho fornito un esempio semplificato di cosa si può fare. Si potrebbe semplicemente escogitare quanto segue per superare il problema: var template = function() { var name = "John Smith"; var message = "Hello, my name is ${name}"; this.local = new Function('return '+ messaggio +';')();}
didinko

No, questo è esattamente ciò che non funzionerebbe - new Functionnon ha accesso a var namenella templatefunzione.
Bergi,

Il secondo colpo risolto il mio problema ... Votami! Grazie, questo ha aiutato a risolvere un problema temporaneo che stavamo riscontrando con il routing dinamico verso un iframe :)
Kris Boyd,

7

Ci sono molte buone soluzioni pubblicate qui, ma nessuna ancora utilizza il metodo String.raw ES6 . Ecco la mia contriubution. Presenta un'importante limitazione in quanto accetterà solo le proprietà da un oggetto passato, il che significa che nessuna esecuzione di codice nel modello funzionerà.

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. Dividi la stringa in parti testuali senza argomento. Vedi regex .
    parts: ["Hello, ", "! Are you ", " years old?"]
  2. Dividi la stringa in nomi di proprietà. Matrice vuota se la corrispondenza fallisce.
    args: ["name", "age"]
  3. Parametri della mappa in objbase al nome della proprietà. La soluzione è limitata dalla mappatura superficiale a un livello. I valori indefiniti vengono sostituiti con una stringa vuota, ma vengono accettati altri valori falsi.
    parameters: ["John Doe", 18]
  4. Utilizzare String.raw(...)e restituire il risultato.

Per curiosità, quale valore offre String.raw qui? Sembra che tu stia facendo tutto il lavoro per analizzare la stringa e tenere traccia di quali sono le sottostazioni. È molto diverso dalla semplice chiamata .replace()ripetuta?
Steve Bennett,

Punto giusto, @SteveBennett. Ho avuto dei problemi nel trasformare una normale stringa in una stringa di modello e ho trovato una soluzione costruendo l'oggetto grezzo da solo. Immagino che riduca String.raw a un metodo di concatenazione, ma penso che funzioni abbastanza bene. Vorrei vedere una buona soluzione .replace(), però :) Penso che la leggibilità sia importante, quindi mentre uso le espressioni regolari, cerco di nominarle per dare un senso a tutto ...
pekaaw

6

Simile alla risposta di Daniel (e alla sostanza di s.meijer ) ma più leggibile:

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

Nota: questo migliora leggermente l'originale di s.meijer, poiché non corrisponderà a cose come ${foo{bar}(la regex consente solo caratteri di parentesi graffe non ricci all'interno ${e }).


AGGIORNAMENTO: Mi è stato chiesto un esempio usando questo, quindi eccoti qui:

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

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

Puoi pubblicare un esempio usando questo? Questo javascript è un po 'oltre me. Suggerirei una regex di /\$\{(.*?)(?!\$\{)\}/g(per gestire le parentesi graffe del nido). Ho una soluzione funzionante ma non sono sicuro che sia portatile come il tuo, quindi mi piacerebbe vedere come dovrebbe essere implementato in una pagina. Anche il mio usa eval().
Regolare Joe

Sono andato avanti e ho anche pubblicato una risposta, e mi piacerebbe molto il tuo feedback su come renderlo più sicuro e attento alle prestazioni: stackoverflow.com/a/48294208 .
Regolare Joe

@RegularJoe Ho aggiunto un esempio. Il mio obiettivo era quello di mantenerlo semplice, ma hai ragione che se vuoi gestire parentesi graffe nidificate, dovrai cambiare la regex. Tuttavia, non riesco a pensare a un caso d'uso per questo quando si valuta una stringa normale come se fosse un modello letterale (l'intero scopo di questa funzione). Cosa avevi in ​​mente?
Matt Browne,

Inoltre, non sono né un esperto di prestazioni né un esperto di sicurezza; la mia risposta è davvero solo combinando due risposte precedenti. Ma dirò che l'uso evalti lascia molto più aperto a possibili errori che potrebbero causare problemi di sicurezza, mentre tutto ciò che la mia versione sta facendo è cercare una proprietà su un oggetto da un percorso separato da punti, che dovrebbe essere sicuro.
Matt Browne,

5

È possibile utilizzare il prototipo di stringa, ad esempio

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

Ma la risposta alla domanda originale non è possibile.


5

Mi è piaciuta la risposta di s.meijer e ho scritto la mia versione basata sulla sua:

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
! Neat Davvero pulito!
xpt,

4

Ho richiesto questo metodo con supporto per Internet Explorer. Si è scoperto che le zecche posteriori non sono supportate nemmeno da IE11. Anche; usare evalo è equivalente Functionnon sembra giusto.

Per quello che nota; Uso anche i backtick, ma questi vengono rimossi da compilatori come Babel. I metodi suggeriti da altri dipendono da essi in fase di esecuzione. Come detto prima; questo è un problema in IE11 e inferiore.

Quindi questo è quello che mi è venuto in mente:

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

Esempio di output:

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 -

"usare eval o la sua equivalente funzione non sembra giusto." ... Sì ... Sono d'accordo, ma penso che questo sia uno dei pochissimi casi d'uso in cui si potrebbe dire "mmhkay, usiamolo". Si prega di controllare jsperf.com/es6-string-tmpl - è il mio caso d'uso pratico. Usando la tua funzione (con la stessa regexp della mia) e la mia (eval + string letterali). Grazie! :)
Andrea Puddu,

@AndreaPuddu, la tua performance è davvero migliore. Ma poi di nuovo; le stringhe di modello non sono supportate in IE. Quindi eval('`' + taggedURL + '`')semplicemente non funziona.
s.meijer,

"Sembra" meglio direi, perché è testato in modo isolato ... L'unico scopo di quel test era quello di vedere i potenziali problemi di prestazioni usando eval. Per quanto riguarda i letterali modello: grazie per averlo sottolineato di nuovo. Sto usando Babel per trascrivere il mio codice ma la mia funzione non funzionerà ancora apparentemente 😐
Andrea Puddu,

3

Al momento non posso commentare le risposte esistenti, quindi non sono in grado di commentare direttamente l'eccellente risposta di Bryan Raynor. Pertanto, questa risposta aggiornerà la sua risposta con una leggera correzione.

In breve, la sua funzione non riesce effettivamente a memorizzare nella cache la funzione creata, quindi verrà sempre ricreata, indipendentemente dal fatto che abbia visto prima il modello. Ecco il codice corretto:

    /**
     * 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, la soluzione funziona alla grande, ma quando l'ho usata in React Native (modalità build), genera un errore: carattere non valido '' ' , sebbene funzioni quando lo eseguo in modalità debug.

Quindi ho scritto la mia soluzione usando regex.

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/

NOTA: Dal momento che non conosco la causa principale di un problema, ho sollevato un ticket nel repository reagente nativo, https://github.com/facebook/react-native/issues/14107 , in modo che una volta che siano in grado di risolvimi / guidami sullo stesso :)


questo supporta i template che contengono il carattere back-tick. Tuttavia, piuttosto che cercare di inventare un modello di modello, probabilmente stai meglio usando solo i baffi o simili . a seconda della complessità dei modelli, si tratta di un approccio a forza bruta che non tiene conto dei casi limite: la chiave potrebbe contenere un modello regex speciale.
SliverNinja - MSFT,

2

Ancora dinamico ma sembra più controllato del semplice utilizzo di un nudo nudo:

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

Questa soluzione funziona senza ES6:

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"

Nota: il Functioncostruttore viene sempre creato nell'ambito globale, il che potrebbe potenzialmente sovrascrivere le variabili globali dal modello, ad es.render("hello ${ someGlobalVar = 'some new value' }", {name:'mo'});


0

Dal momento che stiamo reinventando la ruota su qualcosa che sarebbe una caratteristica adorabile in JavaScript.

Io uso eval(), che non è sicuro, ma JavaScript non è sicuro. Ammetto prontamente che non sono eccellente con JavaScript, ma avevo un bisogno e avevo bisogno di una risposta, quindi ne ho fatta una.

Ho scelto di stilizzare le mie variabili con un @anziché con un $, in particolare perché voglio usare la funzione multilinea dei letterali senza valutare fino a quando non è pronta. Quindi la sintassi variabile è@{OptionalObject.OptionalObjectN.VARIABLE_NAME}

Non sono un esperto di JavaScript, quindi sarei lieto di ricevere consigli sul miglioramento, ma ...

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

Segue un'implementazione molto semplice

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

Nella mia effettiva implementazione, ho scelto di utilizzare @{{variable}}. Un altro set di parentesi graffe. Assurdamente improbabile che lo incontrino inaspettatamente. La regex per questo sarebbe simile/\@\{\{(.*?)(?!\@\{\{)\}\}/g

Per facilitare la lettura

\@\{\{    # 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.

Se non hai esperienza con regex, una regola abbastanza sicura è quella di sfuggire a tutti i caratteri non alfanumerici e non sfuggire mai inutilmente alle lettere poiché molte lettere sfuggite hanno un significato speciale praticamente per tutti i gusti di regex.


0

Dovresti provare questo minuscolo modulo JS, di Andrea Giammarchi, da github: 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 (tutti i seguenti test restituiscono true):

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

Ho creato la mia soluzione facendo un tipo con una descrizione come funzione

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

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

e così facendo:

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

0

Invece di usare eval meglio è usare regex

Eval non è raccomandato e altamente scoraggiato, quindi per favore non usarlo ( mdn eval ).

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

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

funziona per uno, che dire se ho "a è $ {a}, b è {b} ..."?
Leachim
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.