एक स्ट्रिंग को टेम्पलेट स्ट्रिंग में बदलें


147

क्या सामान्य स्ट्रिंग के रूप में टेम्पलेट स्ट्रिंग बनाना संभव है

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

फिर इसे एक टेम्पलेट स्ट्रिंग में परिवर्तित करें

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

बिना eval, new Functionऔर डायनामिक कोड पीढ़ी के अन्य साधन?


5
क्या आपको इसे प्राप्त करने का कोई तरीका मिला? मुझे एक दिन ऐसा करने की आवश्यकता हो सकती है और यह जानने के लिए उत्सुक हूं कि आप क्या कर रहे हैं।
ब्रायन रेनर

@BryanRayner का कहना है कि आपका js प्रोग्राम बाकी API से एक डेटा लाने की कोशिश कर रहा है, जिसका url एक स्ट्रिंग में है। एक "स्ट्रिंग के रूप में फ़ाइल में" / संसाधन / <संसाधन_आईडी> / अपडेट / "और आप अपने प्रोग्राम से गतिशील रूप से" रिसोर्सड आईडी "डाल दें। । जब तक आप उस url को भागों में विभाजित नहीं करना चाहते और विभिन्न क्षेत्रों में सहेजते हैं, तब तक आपको कुछ प्रकार के स्ट्रिंग टेम्पलेट प्रसंस्करण की आवश्यकता होती है।
Ryu_hayabusa


Eval का उपयोग करने के बजाय बेहतर है regex का उपयोग करने के लिए Eval यह अनुशंसित नहीं है और अत्यधिक हतोत्साहित है, इसलिए इसका उपयोग न करें developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…! चलो बी = 10; चलो एक = "बी: $ {बी}"; प्रतिक्रिया दें = a.replace (/ \ $ {\ w +} /, b); conssole.log (प्रतिक्रिया);
विजय पालस्कर

जवाबों:


79

जैसा कि आपके टेम्पलेट स्ट्रिंग को गतिशील रूप सेb (रनटाइम में) चर का संदर्भ प्राप्त करना होगा , इसलिए उत्तर है: नहीं, गतिशील डायनेमिक पीढ़ी के बिना ऐसा करना असंभव है।

लेकिन evalयह बहुत आसान है:

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

7
eval असुरक्षित है, इसलिए डायनामिक कोड जेनरेशन का अन्य साधन है
KOLANICH

8
@KOLANICH विशेष रूप से उस स्थिति के लिए - aस्ट्रिंग में उद्धरणों से बच जाएं और यह बहुत कम असुरक्षित होगा let tpl = eval('`'+a.replace(/`/g,'\\`')+'`');:। मुझे लगता है कि अधिक महत्वपूर्ण यह है कि evalसंकलक को अपने कोड का अनुकूलन करने से रोकें। लेकिन मुझे लगता है कि यह इस सवाल के लिए अप्रासंगिक है।
एलेक्सपॉड्स

3
वास्तव में, आप टेम्पलेट स्ट्रिंग्स के अंदर फ़ंक्शन भी चला सकते हैं।
कोल्हान

9
@KOLANICH आपको नापसंद है eval। हालाँकि, याद रखें कि एक टेम्प्लेट शाब्दिक रूप से स्वयं का एक रूप है eval। दो उदाहरण: var test = Result: ${alert('hello')}; var परीक्षण = Result: ${b=4}; दोनों स्क्रिप्ट के संदर्भ में मनमाना कोड निष्पादित करेंगे। यदि आप मनमाने तार लगाना चाहते हैं, तो आप अनुमति भी दे सकते हैं eval
मानगो

6
सावधान रहे। चूँकि बबैल जैसी कोई चीज इसे ट्रांसप्लांट नहीं करेगी, इसलिए यह कोड IE में काम नहीं करेगा
cgsd

79

अपनी परियोजना में मैंने 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);

अद्यतन मैंने आश्रितता निर्भरता को हटा दिया है, ES6 में कुंजियों और मूल्यों को प्राप्त करने के लिए समकक्ष विधियां हैं।


1
नमस्ते, आपका समाधान बहुत अच्छा काम करता है, लेकिन जब मैंने इसे रिएक्ट नेटिव (बिल्ड मोड) में उपयोग किया, तो यह एक त्रुटि फेंकता है: अमान्य वर्ण '`' , हालांकि यह तब काम करता है जब मैं डीबग मोड में चलता हूं। लगता है, बेबल मुद्दा, कोई मदद?
मोहित पांडे

@MohitPandey मुझे उसी समय त्रुटि हो रही थी जब मैं PhantomJS के तहत इस कोड के परीक्षण चला रहा था और यह क्रोम से गुजर रहा था। अगर ऐसा है, तो मुझे लगता है कि ES6 के लिए बेहतर समर्थन के साथ रास्ते में PhantomJS का नया बीटा संस्करण है, आप इसे स्थापित करने का प्रयास कर सकते हैं।
माट्यूज़ मोस्का

1
दुर्भाग्य से, यह काम नहीं करता है और मैंने उसी के लिए एक regex लिखा है। उत्तर के रूप में अच्छी तरह से जोड़ा गया।
मोहित पांडे

यह समाधान केवल तभी काम करता है यदि बैक-टिक "` "वर्ण टेम्पलेट स्ट्रिंग में मौजूद नहीं है
SliverNinja - MSFT

जब मैं कोशिश करता हूं तो मुझे मिल जाता है ReferenceError: _ is not defined। क्या यह कोड ES6 नहीं बल्कि lodashविशिष्ट है, या ...?
XPT

29

आप यहाँ क्या माँग रहे हैं:

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

समतुल्य है (शक्ति और, एर, सुरक्षा के संदर्भ में) eval: एक स्ट्रिंग युक्त कोड लेने और उस कोड को निष्पादित करने की क्षमता; और कॉलर के वातावरण में स्थानीय चर को देखने के लिए निष्पादित कोड की क्षमता भी है।

जेएस के पास अपने कॉलर में स्थानीय चर देखने के लिए एक फ़ंक्शन के लिए कोई रास्ता नहीं है, जब तक कि वह फ़ंक्शन न हो eval()। यहां तक ​​कि Function()यह भी नहीं कर सकता।


जब आप सुनते हैं कि जावास्क्रिप्ट में आने वाले "टेम्पलेट स्ट्रिंग्स" नामक कुछ है, तो यह मान लेना स्वाभाविक है कि यह एक अंतर्निहित टेम्पलेट लाइब्रेरी है, जैसे मूंछें। यह नहीं है। यह मुख्य रूप से जेएस के लिए सिर्फ स्ट्रिंग इंटरपोलेशन और मल्टीलाइन स्ट्रिंग्स है। मुझे लगता है कि यह थोड़ी देर के लिए एक सामान्य गलत धारणा है, हालांकि। :(


2
टीबीएच वह है जो मैंने सोचा था कि यह था। बहुत, बहुत आसान होता।
ब्रायन रेनर

क्या यह (अभी भी) काम करता है? मुझे मिल रहा है template is not a function
Ionică Bizău

2
इस उत्तर के शीर्ष पर कोड ब्लॉक प्रश्न का एक उद्धरण है। यह काम नहीं करता।
जेसन ओरेंडोर्फ

27

नहीं, डायनेमिक कोड जेनरेशन के बिना ऐसा करने का कोई तरीका नहीं है।

हालांकि, मैंने एक फ़ंक्शन बनाया है जो एक नियमित स्ट्रिंग को एक फ़ंक्शन में बदल देगा, जिसे आंतरिक रूप से टेम्पलेट स्ट्रिंग्स का उपयोग करके मूल्यों के मानचित्र के साथ प्रदान किया जा सकता है।

टेम्पलेट स्ट्रिंग स्ट्रिंग उत्पन्न करें

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

उपयोग:

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

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

आशा है कि यह किसी की मदद करता है। यदि आपको कोड में कोई समस्या आती है, तो कृपया जिस्ट को अपडेट करने के लिए बहुत दयालु बनें।


धन्यवाद! मैंने इसका उपयोग जावास्क्रिप्ट स्प्रिंटफ समाधान के बजाय किया।
२३

1
हर टेम्पलेट के var test = generateTemplateString('/api/${param1}/${param2}/') console.log(test({param1: 'bar', param2: 'foo'}))रिटर्न के लिए काम नहीं करता है/api/bar//
विंसेंट

धन्यवाद, निश्चित। रेगेक्स $ {param1} / $ {param2} का एक एकल मैच शामिल था जब इसे दो मैच होने चाहिए थे।
ब्रायन रेनर

ध्यान दें कि यह एक IE11 में काम नहीं करता है, क्योंकि बैक टिक्स के लिए अनुपलब्ध समर्थन के कारण।
s.meijer

1
बेशक, यदि टेम्पलेट तार एक ब्राउज़र द्वारा समर्थित नहीं हैं, तो यह विधि काम नहीं करेगी। यदि आप असमर्थित ब्राउज़रों में टेम्प्लेट स्ट्रिंग्स का उपयोग करना चाहते हैं, तो मैं टाइपस्क्रिप्ट, या बैबेल जैसे ट्रांसपिलर जैसी भाषा का उपयोग करने की सलाह दूंगा; पुराने ब्राउज़र में ES6 प्राप्त करने का एकमात्र तरीका है।
ब्रायन रेनर

9

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

हर कोई चर तक पहुंचने के बारे में चिंतित है, बस उन्हें पास क्यों नहीं किया जाता है? मुझे यकीन है कि कॉलर में वैरिएबल संदर्भ प्राप्त करने और इसे पारित करने के लिए यह बहुत कठिन नहीं होगा। Obj से प्रॉप्स प्राप्त करने के लिए इस https://stackoverflow.com/a/6394168/6563504 का उपयोग करें । मैं अभी आपके लिए परीक्षण नहीं कर सकता, लेकिन यह काम करना चाहिए।

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

का परीक्षण किया। यहाँ पूरा कोड है।

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 क्या आप विस्तृत कर सकते हैं? मैं इस कोड का सफलतापूर्वक उपयोग कर रहा हूं। jsfiddle.net/w3jx07vt
M3D

1
बेहतर रेगेक्स आपको ${}पात्रों का चयन नहीं करने की अनुमति देगा । कोशिश करें:/(?!\${)([^{}]*)(?=})/g
एरिक होडोंस्की

@Relic jsfiddle.net/w3jx07vt/2 मुझे वह काम नहीं मिला, एक हाथ उधार देने के लिए देखभाल और मैं अपनी पोस्ट को अपडेट करूंगा? :)
M3D

तो जिस तरह से आप इसे हथियाने की कोशिश कर रहे हैं यह वास्तव में बहुत मदद नहीं करेगा, मैंने एक स्ट्रिंग को बदले में समाप्त कर दिया। इंटरपोलेशन के एक चरण को जोड़ने के बजाय, इसलिए मैं स्ट्रिंग को इंटरप या स्ट्रिंग के रूप में उपयोग कर सकता हूं। फैंसी नहीं, लेकिन यह काम किया।
एरिक होडोंस्की

8

यहाँ समस्या एक फ़ंक्शन के लिए है जिसके पास इसके कॉलर के चर तक पहुंच है। यही कारण है कि हम प्रत्यक्ष evalरूप से टेम्प्लेट प्रसंस्करण के लिए उपयोग किए जा रहे हैं । एक संभावित समाधान यह होगा कि किसी शब्दकोश के गुणों द्वारा नामित औपचारिक पैरामीटर लेने वाला एक फ़ंक्शन उत्पन्न किया जाए, और उसी क्रम में संबंधित मूल्यों के साथ इसे कॉल किया जाए। एक वैकल्पिक तरीका यह होगा कि कुछ सरल हो:

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

और किसी को भी बाबेल कंपाइलर का उपयोग करने के लिए हमें क्लोजर बनाने की आवश्यकता है जो उस वातावरण को याद करता है जिसमें इसे बनाया गया था:

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

आपका पहला स्निपेट वास्तव में इससे भी बदतर है evalक्योंकि यह केवल एक वैश्विक nameचर
बर्गी

@Bergi आपका कथन मान्य है - फ़ंक्शन का दायरा खो जाएगा। मैं समस्या का एक आसान समाधान प्रस्तुत करना चाहता था और जो किया जा सकता है उसका एक सरलीकृत उदाहरण प्रदान किया। केवल समस्या को दूर करने के लिए निम्नलिखित के साथ आ सकता है: var template = function() { var name = "John Smith"; var message = "Hello, my name is ${name}"; this.local = new Function('return '+ संदेश +';')();}
didinko

नहीं, यह वही है जो काम नहीं करेगा - फ़ंक्शन में new Functionपहुंच नहीं है । var nametemplate
बर्गी

दूसरे स्निप ने मेरी समस्या तय कर दी ... अप वोट फ्रॉम मी! धन्यवाद, इसने एक अस्थायी समस्या को हल करने में मदद की जो हमें एक iframe में डायनामिक रूटिंग के साथ हो रही थी :)
क्रिश बॉयड

7

यहाँ कई अच्छे समाधान पोस्ट किए गए हैं, लेकिन कोई भी अभी तक ES6 String.raw विधि का उपयोग नहीं करता है । यहां मेरा कंट्रोवर्सी है। इसमें एक महत्वपूर्ण सीमा है कि यह केवल एक पारित वस्तु से गुणों को स्वीकार करेगा, जिसका अर्थ है कि टेम्पलेट में कोई कोड निष्पादन काम नहीं करेगा।

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. गैर-तर्क पाठ भागों में विभाजित स्ट्रिंग। रेगेक्स देखें ।
    parts: ["Hello, ", "! Are you ", " years old?"]
  2. संपत्ति के नामों में विभाजित स्ट्रिंग। यदि मैच विफल रहता है, तो खाली सरणी।
    args: ["name", "age"]
  3. objसंपत्ति के नाम से मानचित्र पैरामीटर । समाधान उथले एक स्तर मानचित्रण द्वारा सीमित है। अपरिभाषित मानों को एक रिक्त स्ट्रिंग के साथ प्रतिस्थापित किया जाता है, लेकिन अन्य गलत मूल्यों को स्वीकार किया जाता है।
    parameters: ["John Doe", 18]
  4. उपयोग String.raw(...)और वापसी परिणाम।

जिज्ञासा से बाहर, String.raw वास्तव में यहाँ क्या प्रदान कर रहा है? ऐसा लगता है कि आप स्ट्रिंग को पार्स करने और सबस्टेशन को ट्रैक करने के सभी काम कर रहे हैं। क्या यह केवल .replace()बार-बार कॉल करने से अलग है ?
स्टीव बेनेट

फेयर पॉइंट, @SteveBennett। मुझे सामान्य स्ट्रिंग को टेम्प्लेट स्ट्रिंग में बदलने में कुछ समस्याएं थीं, और स्वयं कच्ची वस्तु का निर्माण करके एक समाधान पाया। मुझे लगता है कि यह String.raw को कम करने के तरीके को कम करता है, लेकिन मुझे लगता है कि यह काफी अच्छी तरह से काम करता है। मैं इसके साथ एक अच्छा समाधान देखना चाहूंगा .replace(), हालांकि :) मुझे लगता है कि पठनीयता महत्वपूर्ण है, इसलिए नियमित रूप से स्वयं का उपयोग करते समय, मैं उन्हें यह सब समझने में मदद करने के लिए नाम देने की कोशिश करता हूं ...
pekaaw

6

डैनियल के जवाब (और s.meijer के समान सार ), लेकिन अधिक पठनीय:

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

नोट: यह s.meijer के मूल को थोड़ा सुधारता है, क्योंकि यह चीजों से मेल नहीं खाएगा ${foo{bar}(regex केवल गैर-घुंघराले ब्रेस पात्रों को अंदर ${और }) की अनुमति देता है ।


अद्यतन: मुझे इसका उपयोग करने के लिए एक उदाहरण के लिए कहा गया था, इसलिए यहां आप जाएं:

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

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

क्या आप वास्तव में इसका उपयोग करके एक उदाहरण पोस्ट कर सकते हैं? यह जावास्क्रिप्ट मेरे से थोड़ा परे है। मैं सुझाव दूंगा /\$\{(.*?)(?!\$\{)\}/g(घोंसला घुंघराले ब्रेसिज़ को संभालने के लिए)। मेरे पास एक कार्यशील समाधान है, लेकिन मुझे यकीन नहीं है कि यह आपकी तरह पोर्टेबल है, इसलिए मुझे यह देखना अच्छा लगेगा कि इसे एक पृष्ठ में कैसे लागू किया जाना चाहिए। मेरा भी उपयोग करता है eval()
नियमित जो

मैं आगे गया और साथ ही एक उत्तर भी पोस्ट किया, और मुझे आपकी प्रतिक्रिया पसंद आएगी कि कैसे अधिक सुरक्षित और प्रदर्शन-दिमाग बनाया जाए: stackoverflow.com/a/48294208
नियमित जो

@RegularJoe मैंने एक उदाहरण जोड़ा। मेरा लक्ष्य इसे सरल रखना था, लेकिन आप सही हैं कि यदि आप नेस्टेड घुंघराले ब्रेसिज़ को संभालना चाहते हैं, तो आपको रेक्स को बदलना होगा। हालांकि, मैं इसके लिए एक उपयोग के मामले के बारे में नहीं सोच सकता जब एक नियमित स्ट्रिंग का मूल्यांकन करता है जैसे कि यह एक टेम्पलेट शाब्दिक (इस फ़ंक्शन का पूरा उद्देश्य) था। आप के मन में क्या था?
मैट ब्राउन

इसके अलावा, मैं न तो प्रदर्शन विशेषज्ञ हूं और न ही सुरक्षा विशेषज्ञ; मेरा जवाब वास्तव में सिर्फ दो पिछले उत्तरों को मिलाकर है। लेकिन मैं कहूंगा कि evalसुरक्षा की समस्या पैदा करने वाली संभावित गलतियों के लिए आप बहुत अधिक खुले पत्तों का उपयोग कर रहे हैं, जबकि मेरा सभी संस्करण डॉट-अलग किए गए पथ से एक वस्तु पर एक संपत्ति देख रहा है, जो सुरक्षित होना चाहिए।
मैट ब्राउन

5

आप स्ट्रिंग प्रोटोटाइप का उपयोग कर सकते हैं, उदाहरण के लिए

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

लेकिन मूल प्रश्न का उत्तर कोई रास्ता नहीं है।


5

मुझे s.meijer का उत्तर पसंद आया और मैंने अपना संस्करण उसके आधार पर लिखा:

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
साफ! सच में नीट!
XPT

4

मुझे इंटरनेट एक्सप्लोरर के समर्थन के लिए इस विधि की आवश्यकता थी। यह पता चला कि पीछे की टिक भी IE11 द्वारा समर्थित नहीं हैं। इसके अलावा, उपयोग करना evalया इसके बराबर होना Functionसही नहीं लगता है।

उस नोटिस के लिए; मैं भी बैकटिक्स का उपयोग करता हूं, लेकिन इन लोगों को बैबेल जैसे संकलक द्वारा हटा दिया जाता है। अन्य लोगों द्वारा सुझाए गए तरीके, रन-टाइम पर निर्भर करते हैं। जैसा कि पहले कहा गया था; यह IE11 और निम्न में एक समस्या है।

तो यही वह है मुझे जो मिला है:

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

उदाहरण आउटपुट:

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 का उपयोग करना या इसके बराबर कार्य करना सही नहीं लगता है।" ... हाँ ... मैं सहमत हूं, लेकिन मुझे लगता है कि यह बहुत कम उपयोग के मामलों में से एक है जिसमें कोई भी कह सकता है, "एमएमके, चलो इसका उपयोग करें"। कृपया jsperf.com/es6-string-tmpl जांचें - यह मेरा व्यावहारिक उपयोग मामला है। अपने फ़ंक्शन (मेरा के रूप में एक ही regexp के साथ) और मेरा (eval + स्ट्रिंग शाब्दिक) का उपयोग करना। धन्यवाद! :)
एंड्रिया पुड्डू

@AndreaPuddu, आपका प्रदर्शन वास्तव में बेहतर है। लेकिन उसके बाद फिर से; टेम्पलेट तार IE में असमर्थित हैं। तो eval('`' + taggedURL + '`')बस काम नहीं करता है।
s.meijer

"लगता है" मैं बेहतर कहूंगा, क्योंकि यह अलगाव में परीक्षण किया गया है ... उस परीक्षण का एकमात्र उद्देश्य संभावित प्रदर्शन के मुद्दों का उपयोग करना था eval। टेम्पलेट शाब्दिक के बारे में: फिर से इंगित करने के लिए धन्यवाद। मैं अपने कोड को ट्रांसपेल करने के लिए बैबेल का उपयोग कर रहा हूं, लेकिन मेरा कार्य अभी भी स्पष्ट रूप से काम नहीं करेगा rea
एंड्रिया पुड्डू

3

मैं वर्तमान में मौजूदा उत्तरों पर टिप्पणी नहीं कर सकता, इसलिए मैं सीधे ब्रायन रेन्नोर की उत्कृष्ट प्रतिक्रिया पर टिप्पणी करने में असमर्थ हूं। इस प्रकार, यह प्रतिक्रिया उनके उत्तर को थोड़े सुधार के साथ अपडेट करने जा रही है।

संक्षेप में, उनका फ़ंक्शन वास्तव में बनाए गए फ़ंक्शन को कैश करने में विफल रहता है, इसलिए यह हमेशा रीक्रिएट करेगा, भले ही पहले इसका टेम्प्लेट देखा गया हो या नहीं। यहाँ सही कोड है:

    /**
     * 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 मोस्का, समाधान बहुत अच्छा काम करता है, लेकिन जब मैंने इसे रिएक्ट नेटिव (बिल्ड मोड) में उपयोग किया, तो यह एक त्रुटि फेंकता है: अमान्य वर्ण '`' , हालांकि यह तब काम करता है जब मैं इसे डीबग मोड में चलाता हूं।

इसलिए मैंने 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)

डेमो: https://es6console.com/j31pqx1p/

ध्यान दें: चूंकि मुझे किसी समस्या के मूल कारण का पता नहीं है, इसलिए मैंने प्रतिक्रिया-देशी रेपो, https://github.com/facebook/react-native/issues/14107 में एक टिकट उठाया , ताकि एक बार वे इसमें सक्षम हो सकें ठीक करें / मुझे उसी के बारे में मार्गदर्शन करें :)


यह बैक-टिक चरित्र वाले टेम्प्लेट का समर्थन करता है। हालांकि, एक टेम्प्लेटिंग पैटर्न का आविष्कार करने की कोशिश के बजाय, आप शायद मूंछें या इसी तरह का उपयोग करके बेहतर हैं । आपके टेम्प्लेट कितने जटिल हैं, इसके आधार पर यह एक ब्रूट फोर्स अप्रोच है जो एज के मामलों पर विचार नहीं करता है - कुंजी में विशेष रेगेक्स पैटर्न हो सकता है।
स्लीवरनिंजा - MSFT

2

अभी भी गतिशील है, लेकिन नग्न नग्न का उपयोग करने की तुलना में अधिक नियंत्रित लगता है:

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

यह समाधान 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"

नोट: Functionकंस्ट्रक्टर हमेशा वैश्विक दायरे में बनाया जाता है, जो संभावित रूप से वैश्विक चर को टेम्पलेट द्वारा अधिलेखित करने का कारण बन सकता है, आदि।render("hello ${ someGlobalVar = 'some new value' }", {name:'mo'});


0

चूँकि हम पहिया को किसी ऐसी चीज़ पर पुनर्निर्मित कर रहे हैं जो जावास्क्रिप्ट में एक सुंदर विशेषता होगी।

मैं उपयोग करता हूं eval(), जो सुरक्षित नहीं है, लेकिन जावास्क्रिप्ट सुरक्षित नहीं है। मैं आसानी से मानता हूं कि मैं जावास्क्रिप्ट के साथ उत्कृष्ट नहीं हूं, लेकिन मुझे एक आवश्यकता थी, और मुझे उत्तर की आवश्यकता थी इसलिए मैंने एक बना दिया।

मैंने अपने चरों को एक के @बजाय एक $विशेष रूप से स्टाइल करने के लिए चुना , विशेष रूप से क्योंकि मैं टिल का मूल्यांकन किए बिना शाब्दिक की बहुस्तरीय सुविधा का उपयोग करना चाहता हूं । तो चर वाक्यविन्यास है@{OptionalObject.OptionalObjectN.VARIABLE_NAME}

मैं कोई जावास्क्रिप्ट विशेषज्ञ नहीं हूं, इसलिए मैं ख़ुशी से सुधार पर सलाह लेना चाहूंगा लेकिन ...

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

एक बहुत ही सरल कार्यान्वयन इस प्रकार है

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

मेरे वास्तविक कार्यान्वयन में, मैं उपयोग करना चुनता हूं @{{variable}}। ब्रेसिज़ का एक और सेट। अप्रत्याशित रूप से उस अप्रत्याशित रूप से मुठभेड़ की संभावना नहीं है। उस के लिए regex जैसा दिखेगा/\@\{\{(.*?)(?!\@\{\{)\}\}/g

ताकि पढ़ने में आसानी हो

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

यदि आप regex के साथ अनुभव नहीं कर रहे हैं, तो एक बहुत ही सुरक्षित नियम हर गैर-अल्फ़ान्यूमेरिक वर्ण से बचने के लिए है, और कभी भी अनावश्यक रूप से अक्षरों से बचना नहीं है क्योंकि कई बच गए पत्रों का विशेष रूप से regex के सभी स्वादों के लिए विशेष अर्थ है।


0

आपको इस छोटे जेएस मॉड्यूल की कोशिश करनी चाहिए, एंड्रिया जियामारची द्वारा, जीथब से: 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);
};

डेमो (सभी निम्नलिखित परीक्षण सही हैं):

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

मैंने एक फ़ंक्शन के रूप में वर्णन के साथ एक प्रकार करते हुए अपना स्वयं का समाधान बनाया

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

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

और ऐसा कर रहे हैं:

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

0

Eval का उपयोग करने के बजाय बेहतर regex का उपयोग करना है

यह अनुशंसित नहीं है और अत्यधिक हतोत्साहित किया गया है, इसलिए इसका इस्तेमाल न करें ( mdn eval )।

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

let response = a.replace(/\${\w+}/ ,b);
conssole.log(response);
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.