Reputation: 33
Hi everyone I need to write a function that takes a string and object and interpolates that object in the string so something like this
// interpolate("Its {weather} outside", {weather: 'damn Hot'})
// returns 'It's damn hot outside'
// interpolate( "Hi my name is {name}", {name: 'John'});
// returns 'Hi my name is John'
It should also no matter how deep the object goes so a case like this
// interpolate("Hi my name is {contact.name}", {contact: {name: 'john'}});
Im a little stuck and at first I tried splitting up the string into an array then trying to fit the object value in the array then join that back together but that has not worked for all test cases, can someone help me write this function and explain their solution please? Thankyou
so I tried something like this but does not really work for all test cases, this is a template literal but the function should just work giving those values as arguments on its own, otherwise I'm pretty stuck . .
function interpolate(strings, ...keys) {
return (function(...values) {
var dict = values[values.length - 1] || {};
var result = [strings[0]];
keys.forEach(function(key, i) {
var value = Number.isInteger(key) ? values[key] : dict[key];
result.push(value, strings[i + 1]);
});
return result.join('');
});
}
var t1Closure = interpolate`${0}${1}${0}!`;
t1Closure('Y', 'A'); // "YAY!"
var t2Closure = interpolate`${0} ${'foo'}!`;
console.log(t2Closure('Hello', {foo: 'World'})); // "Hello World!"
ok I'm getting closer so I separated the problem into two functions and need to combine them, the only thing is I'm not sure how to get the last use case to work without template literals
var something = "something";
var sub = function(str) {
return str.replace(/#\{(.*?)\}/g,
function(whole, expr) {
return eval(expr)
})
}
console.log(sub("hello #{something}"));
var objectValue = function(str, obj){
for(key in obj) {
if(obj.hasOwnProperty(key)) {
var value = obj[key];
return str + value;
}
}
}
console.log(objectValue("hi my name is ", {contact: {name: 'john'}}));
Upvotes: 3
Views: 452
Reputation: 5038
Here you go:
'use strict';
function interpolate(str, obj) {
for (let prop in obj) {
if (obj.hasOwnProperty(prop)) {
str = str.replace(new RegExp(`{${prop}}`, 'g'), obj[prop]);
}
}
return str;
}
console.log(interpolate("Its {weather} outside", {weather: 'damn Hot'}));
// Its damn Hot outside
Upvotes: 1
Reputation: 13640
A little late to the party, but in case you cannot (don't want to) use any external libraries or ES6, here is the idea:
function getMatches(s) {
var regExp = /{([^}]*)}/g,
matches = [],
match;
while ((match = regExp.exec(s)) != null) {
matches.push(match[1]);
}
return matches;
}
function objValue(obj, i) {
return obj[i];
}
function interpolate(s, obj) {
var matches = getMatches(s),
result = s;
matches.forEach(function (match) {
var props = match.split('.'),
value = props.reduce(objValue, obj) || '';
result = result.replace('{' + match + '}', value);
});
return result;
}
Usage
interpolate("Its {weather} outside", { weather: 'damn Hot' });
Upvotes: 0
Reputation: 350310
eval
If you control the string that you pass and consider it safe, you can use eval
:
function interpolate (str, obj) {
return str.replace(/\{(.*?)\}/g, function (_, ref) {
return eval('obj.' + ref);
});
}
var output = interpolate("Its {weather} outside", {weather: 'damn Hot'});
console.log(output);
output = interpolate("Hi my name is {contact.name}", {contact: {name: 'john'}});
console.log(output);
output = interpolate("The highest bid is {rank[0].bid}", {rank: [{bid: 900}, {bid:600}]});
console.log(output);
Be aware that if given a string like '{x;alert("hi")}'
, the above function would execute that alert
, or any code that is put instead. So this is not a good solution if the string is provided (or can be altered) by the user.
It does not follow your function descriptor, but template literals already offer the functionality you are looking for:
var weather = 'damn Hot';
var output = `It's ${weather} outside`;
console.log(output);
var contact = {name: 'john'};
var output = `Hi my name is ${contact.name}`;
console.log(output);
Upvotes: 3
Reputation: 8096
Or lodash templates. Lodash already has a lot of handy features you end up using a lot of in my opinion.
var str = _.template('Its <%= weather %> outside')({weather: 'damn Hot'});
// If you wanted to use the {{:var}} syntax.
_.templateSettings.interpolate = /{{:([\s\S]+?)}}/g;
var str = _.template('Its {{:weather}} outside')({weather: 'damn Hot'});
Upvotes: 0