Related
Consider this code:
var age = 3;
console.log("I'm " + age + " years old!");
Are there any other ways to insert the value of a variable in to a string, apart from string concatenation?
Since ES6, you can use template literals:
const age = 3
console.log(`I'm ${age} years old!`)
P.S. Note the use of backticks: ``.
tl;dr
Use ECMAScript 2015's Template String Literals, if applicable.
Explanation
There is no direct way to do it, as per ECMAScript 5 specifications, but ECMAScript 6 has template strings, which were also known as quasi-literals during the drafting of the spec. Use them like this:
> var n = 42;
undefined
> `foo${n}bar`
'foo42bar'
You can use any valid JavaScript expression inside the {}. For example:
> `foo${{name: 'Google'}.name}bar`
'fooGooglebar'
> `foo${1 + 3}bar`
'foo4bar'
The other important thing is, you don't have to worry about multi-line strings anymore. You can write them simply as
> `foo
... bar`
'foo\n bar'
Note: I used io.js v2.4.0 to evaluate all the template strings shown above. You can also use the latest Chrome to test the above shown examples.
Note: ES6 Specifications are now finalized, but have yet to be implemented by all major browsers. According to the Mozilla Developer Network pages, this will be implemented for basic support starting in the following versions: Firefox 34, Chrome 41, Internet Explorer 12. If you're an Opera, Safari, or Internet Explorer user and are curious about this now, this test bed can be used to play around until everyone gets support for this.
Douglas Crockford's Remedial JavaScript includes a String.prototype.supplant function. It is short, familiar, and easy to use:
String.prototype.supplant = function (o) {
return this.replace(/{([^{}]*)}/g,
function (a, b) {
var r = o[b];
return typeof r === 'string' || typeof r === 'number' ? r : a;
}
);
};
// Usage:
alert("I'm {age} years old!".supplant({ age: 29 }));
alert("The {a} says {n}, {n}, {n}!".supplant({ a: 'cow', n: 'moo' }));
If you don't want to change String's prototype, you can always adapt it to be standalone, or place it into some other namespace, or whatever.
Word of caution: avoid any template system which does't allow you to escape its own delimiters. For example, There would be no way to output the following using the supplant() method mentioned here.
"I am 3 years old thanks to my {age} variable."
Simple interpolation may work for small self-contained scripts, but often comes with this design flaw that will limit any serious use. I honestly prefer DOM templates, such as:
<div> I am <span id="age"></span> years old!</div>
And use jQuery manipulation: $('#age').text(3)
Alternately, if you are simply just tired of string concatenation, there's always alternate syntax:
var age = 3;
var str = ["I'm only", age, "years old"].join(" ");
I use this pattern in a lot of languages when I don't know how to do it properly yet and just want to get an idea down quickly:
// JavaScript
let stringValue = 'Hello, my name is {name}. You {action} my {relation}.'
.replace(/{name}/g ,'Inigo Montoya')
.replace(/{action}/g ,'killed')
.replace(/{relation}/g,'father')
;
While not particularily efficient, I find it readable. It always works, and its always available:
' VBScript
dim template = "Hello, my name is {name}. You {action} my {relation}."
dim stringvalue = template
stringValue = replace(stringvalue, "{name}" ,"Luke Skywalker")
stringValue = replace(stringvalue, "{relation}","Father")
stringValue = replace(stringvalue, "{action}" ,"are")
ALWAYS
* COBOL
INSPECT stringvalue REPLACING FIRST '{name}' BY 'Grendel Mother'
INSPECT stringvalue REPLACING FIRST '{relation}' BY 'Son shoulder'
INSPECT stringvalue REPLACING FIRST '{action}' BY 'made a gaping mortal-making wound upon.'
You could use Prototype's template system if you really feel like using a sledgehammer to crack a nut:
var template = new Template("I'm #{age} years old!");
alert(template.evaluate({age: 21}));
Try sprintf library (a complete open source JavaScript sprintf implementation). For example:
vsprintf('The first 4 letters of the english alphabet are: %s, %s, %s and %s', ['a', 'b', 'c', 'd']);
vsprintf takes an array of arguments and returns a formatted string.
If you want to interpolate in console.log output, then just
console.log("Eruption 1: %s", eruption1);
^^
Here, %s is what is called a "format specifier". console.log has this sort of interpolation support built-in.
You can do easily using ES6 template string and transpile to ES5 using any available transpilar like babel.
const age = 3;
console.log(`I'm ${age} years old!`);
http://www.es6fiddle.net/im3c3euc/
The simplest would be
`my string ${VARIABLE}`
a less efficient way to accomplish this would be
function format(str, ...params) {
for(const param of params)
str = str.replace("%", param);
return str;
}
which can be used with
format("My % string", "interpolation")
let age = 3;
console.log(`I'm ${age} years old!`);
You can use the backticks `` and ES6 template string
Try kiwi, a light-weight JavaScript module for string interpolation.
You can do
Kiwi.compose("I'm % years old!", [age]);
or
Kiwi.compose("I'm %{age} years old!", {"age" : age});
Here's a solution which requires you to provide an object with the values. If you don't provide an object as parameter, it will default to using global variables. But better stick to using the parameter, it's much cleaner.
String.prototype.interpolate = function(props) {
return this.replace(/\{(\w+)\}/g, function(match, expr) {
return (props || window)[expr];
});
};
// Test:
// Using the parameter (advised approach)
document.getElementById("resultA").innerText = "Eruption 1: {eruption1}".interpolate({ eruption1: 112 });
// Using the global scope
var eruption2 = 116;
document.getElementById("resultB").innerText = "Eruption 2: {eruption2}".interpolate();
<div id="resultA"></div><div id="resultB"></div>
Couldn't find what I was looking for, then found it -
If you're using Node.js, there's a built-in utilpackage with a format function that works like this:
util.format("Hello my name is %s", "Brent");
> Hello my name is Brent
Coincidentally this is now built into console.log flavors too in Node.js -
console.log("This really bad error happened: %s", "ReferenceError");
> This really bad error happened: ReferenceError
Expanding on Greg Kindel's second answer, you can write a function to eliminate some of the boilerplate:
var fmt = {
join: function() {
return Array.prototype.slice.call(arguments).join(' ');
},
log: function() {
console.log(this.join(...arguments));
}
}
Usage:
var age = 7;
var years = 5;
var sentence = fmt.join('I am now', age, 'years old!');
fmt.log('In', years, 'years I will be', age + years, 'years old!');
I can show you with an example:
function fullName(first, last) {
let fullName = first + " " + last;
return fullName;
}
function fullNameStringInterpolation(first, last) {
let fullName = `${first} ${last}`;
return fullName;
}
console.log('Old School: ' + fullName('Carlos', 'Gutierrez'));
console.log('New School: ' + fullNameStringInterpolation('Carlos', 'Gutierrez'));
Since ES6, if you want to do string interpolation in object keys, you will get a SyntaxError: expected property name, got '${' if you do something like:
let age = 3
let obj = { `${age}`: 3 }
You should do the following instead:
let obj = { [`${age}`]: 3 }
Supplant more for ES6 version of #Chris Nielsen's post.
String.prototype.supplant = function (o) {
return this.replace(/\${([^\${}]*)}/g,
(a, b) => {
var r = o[b];
return typeof r === 'string' || typeof r === 'number' ? r : a;
}
);
};
string = "How now ${color} cow? {${greeting}}, ${greeting}, moo says the ${color} cow.";
string.supplant({color: "brown", greeting: "moo"});
=> "How now brown cow? {moo}, moo, moo says the brown cow."
Using template syntax fails in older browsers, important if you are creating HTML for public use. Using concatenation is tedious and hard to read, particularly if you have many or long expressions, or if you must use parentheses to handle mixtures of number and string items (both of which use the + operator).
PHP expands quoted strings containing variables and even some expressions using a very compact notation: $a="the color is $color";
In JavaScript, an efficient function can be written to support this: var a=S('the color is ',color);, using a variable number of arguments. While there is no advantage over concatenation in this example, when the expressions get longer this syntax may be clearer. Or one can use the dollar sign to signal the start of an expression using a JavaScript function, as in PHP.
On the other hand, writing an efficient workaround function to provide template-like expansion of strings for older browsers wouldn't be hard. Someone has probably done it already.
Finally, I imagine that sprintf (as in C, C++, and PHP) could be written in JavaScript, although it would be a little less efficient than these other solutions.
Custom flexible interpolation:
var sourceElm = document.querySelector('input')
// interpolation callback
const onInterpolate = s => `<mark>${s}</mark>`
// listen to "input" event
sourceElm.addEventListener('input', parseInput)
// parse on window load
parseInput()
// input element parser
function parseInput(){
var html = interpolate(sourceElm.value, undefined, onInterpolate)
sourceElm.nextElementSibling.innerHTML = html;
}
// the actual interpolation
function interpolate(str, interpolator = ["{{", "}}"], cb){
// split by "start" pattern
return str.split(interpolator[0]).map((s1, i) => {
// first item can be safely ignored
if( i == 0 ) return s1;
// for each splited part, split again by "end" pattern
const s2 = s1.split(interpolator[1]);
// is there's no "closing" match to this part, rebuild it
if( s1 == s2[0]) return interpolator[0] + s2[0]
// if this split's result as multiple items' array, it means the first item is between the patterns
if( s2.length > 1 ){
s2[0] = s2[0]
? cb(s2[0]) // replace the array item with whatever
: interpolator.join('') // nothing was between the interpolation pattern
}
return s2.join('') // merge splited array (part2)
}).join('') // merge everything
}
input{
padding:5px;
width: 100%;
box-sizing: border-box;
margin-bottom: 20px;
}
*{
font: 14px Arial;
padding:5px;
}
<input value="Everything between {{}} is {{processed}}" />
<div></div>
While templates are probably best for the case you describe, if you have or want your data and/or arguments in iterable/array form, you can use String.raw.
String.raw({
raw: ["I'm ", " years old!"]
}, 3);
With the data as an array, one can use the spread operator:
const args = [3, 'yesterday'];
String.raw({
raw: ["I'm ", " years old as of ", ""]
}, ...args);
This question already has answers here:
How to call native es6 template string replacement from tag function?
(4 answers)
Closed 2 years ago.
My goal is to write a tagged template function like
myTemplateTagFunction`some text ${variable} etc. etc.`
...that behaves like the default template literal function in javascript.
My first attempt was
let myTaggedTemplate = args => `${args}`
But this breaks pretty quickly...
> myTaggedTemplate`hello world ${2 + 5}`
// "hello world ,"
> `hello world ${2 + 5}`
// "hello world 7"
There must be an easier way to do this that I'm missing?
There's perhaps a shorter way to do it, but this is my approach:
const myTaggedTemplate = (strings, ...vars) => {
let result = '';
strings.forEach((str, i) => {
result += `${str}${i === strings.length - 1 ? '' : vars[i]}`;
});
return result;
};
How to define a tagged template function
If you define a tagged template function, it has to receive an array of strings as first argument and expressions of arbitrary number as subsequent parameters. The strings are all string between your inserted expressions (between all ${...}) and all expressions are the values of what you put into ${...}.
Example code
let numExp = 2;
function tagFunction(strings, ...expressions) {
let returnString = "";
for (let i = 0; i < expressions.length; i++) {
returnString += strings[i] + expressions[i];
}
returnString += strings[strings.length - 1];
return returnString;
}
console.log(
tagFunction`Using function \"${tagFunction.name}\" with ${numExp} expressions`
);
You need to change your function:
let myTaggedTemplate = (strings,...values) => ...;
and try to follow the example in this link
This question already has answers here:
How to match string within parentheses (nested) in Java?
(2 answers)
Closed 4 years ago.
I have the following:
POLYGON((7.593955993652344 33.70124816894531,3.1060409545898438 24.7247314453125,8.64349365234375 22.052650451660156,14.989128112792969 26.966629028320312,7.593955993652344 33.70124816894531))
I can also have the following:
POLYGON(7.593955993652344 33.70124816894531,3.1060409545898438 24.7247314453125,8.64349365234375 22.052650451660156,14.989128112792969 26.966629028320312,7.593955993652344 33.70124816894531)
Noting the difference in parens. I only always wants the data inside the innermost set of parents so I can split on the commas.
I had something like this let coordFinder = /\(([^)]+)\)/g; but it's not getting me both cases.
let coordFinder = /.*\((.*?)\)/;
var test1 = '((abc(123,456)))';
var test2 = '(abc)';
console.log('result in test1: ' + test1.match(coordFinder)[1]);
console.log('result in test2: ' + test2.match(coordFinder)[1]);
You could do one of the following:
\([^()]*\)
Or, getting down to the digits and dots and commas,
\([.,0-9 ]*\)
UPDATE: added snippet (works as expected) => matches both versions with one or two sets of parameters
var poly2 = "POLYGON((7.593955993652344 33.70124816894531,3.1060409545898438 24.7247314453125,8.64349365234375 22.052650451660156,14.989128112792969 26.966629028320312,7.593955993652344 33.70124816894531))",
poly1 = "POLYGON(7.593955993652344 33.70124816894531,3.1060409545898438 24.7247314453125,8.64349365234375 22.052650451660156,14.989128112792969 26.966629028320312,7.593955993652344 33.70124816894531)";
console.log(poly1.match(/\([.,0-9 ]*\)/));
console.log(poly2.match(/\([.,0-9 ]*\)/));
Consider this code:
var age = 3;
console.log("I'm " + age + " years old!");
Are there any other ways to insert the value of a variable in to a string, apart from string concatenation?
Since ES6, you can use template literals:
const age = 3
console.log(`I'm ${age} years old!`)
P.S. Note the use of backticks: ``.
tl;dr
Use ECMAScript 2015's Template String Literals, if applicable.
Explanation
There is no direct way to do it, as per ECMAScript 5 specifications, but ECMAScript 6 has template strings, which were also known as quasi-literals during the drafting of the spec. Use them like this:
> var n = 42;
undefined
> `foo${n}bar`
'foo42bar'
You can use any valid JavaScript expression inside the {}. For example:
> `foo${{name: 'Google'}.name}bar`
'fooGooglebar'
> `foo${1 + 3}bar`
'foo4bar'
The other important thing is, you don't have to worry about multi-line strings anymore. You can write them simply as
> `foo
... bar`
'foo\n bar'
Note: I used io.js v2.4.0 to evaluate all the template strings shown above. You can also use the latest Chrome to test the above shown examples.
Note: ES6 Specifications are now finalized, but have yet to be implemented by all major browsers. According to the Mozilla Developer Network pages, this will be implemented for basic support starting in the following versions: Firefox 34, Chrome 41, Internet Explorer 12. If you're an Opera, Safari, or Internet Explorer user and are curious about this now, this test bed can be used to play around until everyone gets support for this.
Douglas Crockford's Remedial JavaScript includes a String.prototype.supplant function. It is short, familiar, and easy to use:
String.prototype.supplant = function (o) {
return this.replace(/{([^{}]*)}/g,
function (a, b) {
var r = o[b];
return typeof r === 'string' || typeof r === 'number' ? r : a;
}
);
};
// Usage:
alert("I'm {age} years old!".supplant({ age: 29 }));
alert("The {a} says {n}, {n}, {n}!".supplant({ a: 'cow', n: 'moo' }));
If you don't want to change String's prototype, you can always adapt it to be standalone, or place it into some other namespace, or whatever.
Word of caution: avoid any template system which does't allow you to escape its own delimiters. For example, There would be no way to output the following using the supplant() method mentioned here.
"I am 3 years old thanks to my {age} variable."
Simple interpolation may work for small self-contained scripts, but often comes with this design flaw that will limit any serious use. I honestly prefer DOM templates, such as:
<div> I am <span id="age"></span> years old!</div>
And use jQuery manipulation: $('#age').text(3)
Alternately, if you are simply just tired of string concatenation, there's always alternate syntax:
var age = 3;
var str = ["I'm only", age, "years old"].join(" ");
I use this pattern in a lot of languages when I don't know how to do it properly yet and just want to get an idea down quickly:
// JavaScript
let stringValue = 'Hello, my name is {name}. You {action} my {relation}.'
.replace(/{name}/g ,'Inigo Montoya')
.replace(/{action}/g ,'killed')
.replace(/{relation}/g,'father')
;
While not particularily efficient, I find it readable. It always works, and its always available:
' VBScript
dim template = "Hello, my name is {name}. You {action} my {relation}."
dim stringvalue = template
stringValue = replace(stringvalue, "{name}" ,"Luke Skywalker")
stringValue = replace(stringvalue, "{relation}","Father")
stringValue = replace(stringvalue, "{action}" ,"are")
ALWAYS
* COBOL
INSPECT stringvalue REPLACING FIRST '{name}' BY 'Grendel Mother'
INSPECT stringvalue REPLACING FIRST '{relation}' BY 'Son shoulder'
INSPECT stringvalue REPLACING FIRST '{action}' BY 'made a gaping mortal-making wound upon.'
You could use Prototype's template system if you really feel like using a sledgehammer to crack a nut:
var template = new Template("I'm #{age} years old!");
alert(template.evaluate({age: 21}));
Try sprintf library (a complete open source JavaScript sprintf implementation). For example:
vsprintf('The first 4 letters of the english alphabet are: %s, %s, %s and %s', ['a', 'b', 'c', 'd']);
vsprintf takes an array of arguments and returns a formatted string.
If you want to interpolate in console.log output, then just
console.log("Eruption 1: %s", eruption1);
^^
Here, %s is what is called a "format specifier". console.log has this sort of interpolation support built-in.
You can do easily using ES6 template string and transpile to ES5 using any available transpilar like babel.
const age = 3;
console.log(`I'm ${age} years old!`);
http://www.es6fiddle.net/im3c3euc/
The simplest would be
`my string ${VARIABLE}`
a less efficient way to accomplish this would be
function format(str, ...params) {
for(const param of params)
str = str.replace("%", param);
return str;
}
which can be used with
format("My % string", "interpolation")
let age = 3;
console.log(`I'm ${age} years old!`);
You can use the backticks `` and ES6 template string
Try kiwi, a light-weight JavaScript module for string interpolation.
You can do
Kiwi.compose("I'm % years old!", [age]);
or
Kiwi.compose("I'm %{age} years old!", {"age" : age});
Here's a solution which requires you to provide an object with the values. If you don't provide an object as parameter, it will default to using global variables. But better stick to using the parameter, it's much cleaner.
String.prototype.interpolate = function(props) {
return this.replace(/\{(\w+)\}/g, function(match, expr) {
return (props || window)[expr];
});
};
// Test:
// Using the parameter (advised approach)
document.getElementById("resultA").innerText = "Eruption 1: {eruption1}".interpolate({ eruption1: 112 });
// Using the global scope
var eruption2 = 116;
document.getElementById("resultB").innerText = "Eruption 2: {eruption2}".interpolate();
<div id="resultA"></div><div id="resultB"></div>
Couldn't find what I was looking for, then found it -
If you're using Node.js, there's a built-in utilpackage with a format function that works like this:
util.format("Hello my name is %s", "Brent");
> Hello my name is Brent
Coincidentally this is now built into console.log flavors too in Node.js -
console.log("This really bad error happened: %s", "ReferenceError");
> This really bad error happened: ReferenceError
Expanding on Greg Kindel's second answer, you can write a function to eliminate some of the boilerplate:
var fmt = {
join: function() {
return Array.prototype.slice.call(arguments).join(' ');
},
log: function() {
console.log(this.join(...arguments));
}
}
Usage:
var age = 7;
var years = 5;
var sentence = fmt.join('I am now', age, 'years old!');
fmt.log('In', years, 'years I will be', age + years, 'years old!');
I can show you with an example:
function fullName(first, last) {
let fullName = first + " " + last;
return fullName;
}
function fullNameStringInterpolation(first, last) {
let fullName = `${first} ${last}`;
return fullName;
}
console.log('Old School: ' + fullName('Carlos', 'Gutierrez'));
console.log('New School: ' + fullNameStringInterpolation('Carlos', 'Gutierrez'));
Since ES6, if you want to do string interpolation in object keys, you will get a SyntaxError: expected property name, got '${' if you do something like:
let age = 3
let obj = { `${age}`: 3 }
You should do the following instead:
let obj = { [`${age}`]: 3 }
Supplant more for ES6 version of #Chris Nielsen's post.
String.prototype.supplant = function (o) {
return this.replace(/\${([^\${}]*)}/g,
(a, b) => {
var r = o[b];
return typeof r === 'string' || typeof r === 'number' ? r : a;
}
);
};
string = "How now ${color} cow? {${greeting}}, ${greeting}, moo says the ${color} cow.";
string.supplant({color: "brown", greeting: "moo"});
=> "How now brown cow? {moo}, moo, moo says the brown cow."
Using template syntax fails in older browsers, important if you are creating HTML for public use. Using concatenation is tedious and hard to read, particularly if you have many or long expressions, or if you must use parentheses to handle mixtures of number and string items (both of which use the + operator).
PHP expands quoted strings containing variables and even some expressions using a very compact notation: $a="the color is $color";
In JavaScript, an efficient function can be written to support this: var a=S('the color is ',color);, using a variable number of arguments. While there is no advantage over concatenation in this example, when the expressions get longer this syntax may be clearer. Or one can use the dollar sign to signal the start of an expression using a JavaScript function, as in PHP.
On the other hand, writing an efficient workaround function to provide template-like expansion of strings for older browsers wouldn't be hard. Someone has probably done it already.
Finally, I imagine that sprintf (as in C, C++, and PHP) could be written in JavaScript, although it would be a little less efficient than these other solutions.
Custom flexible interpolation:
var sourceElm = document.querySelector('input')
// interpolation callback
const onInterpolate = s => `<mark>${s}</mark>`
// listen to "input" event
sourceElm.addEventListener('input', parseInput)
// parse on window load
parseInput()
// input element parser
function parseInput(){
var html = interpolate(sourceElm.value, undefined, onInterpolate)
sourceElm.nextElementSibling.innerHTML = html;
}
// the actual interpolation
function interpolate(str, interpolator = ["{{", "}}"], cb){
// split by "start" pattern
return str.split(interpolator[0]).map((s1, i) => {
// first item can be safely ignored
if( i == 0 ) return s1;
// for each splited part, split again by "end" pattern
const s2 = s1.split(interpolator[1]);
// is there's no "closing" match to this part, rebuild it
if( s1 == s2[0]) return interpolator[0] + s2[0]
// if this split's result as multiple items' array, it means the first item is between the patterns
if( s2.length > 1 ){
s2[0] = s2[0]
? cb(s2[0]) // replace the array item with whatever
: interpolator.join('') // nothing was between the interpolation pattern
}
return s2.join('') // merge splited array (part2)
}).join('') // merge everything
}
input{
padding:5px;
width: 100%;
box-sizing: border-box;
margin-bottom: 20px;
}
*{
font: 14px Arial;
padding:5px;
}
<input value="Everything between {{}} is {{processed}}" />
<div></div>
While templates are probably best for the case you describe, if you have or want your data and/or arguments in iterable/array form, you can use String.raw.
String.raw({
raw: ["I'm ", " years old!"]
}, 3);
With the data as an array, one can use the spread operator:
const args = [3, 'yesterday'];
String.raw({
raw: ["I'm ", " years old as of ", ""]
}, ...args);
This question already has answers here:
Get global variable dynamically by name string in JavaScript
(6 answers)
Closed 5 years ago.
I want to be able to pass a string into a function, concatenate it with a common suffix, and use that new string as an existing variable. For example,
var firstInfo = "The first string says this.";
var secondInfo = "The second says that.";
updateInfo(arg)
{
console.log(arg + "Info");
}
updateInfo("first");
/* Should print "The first string says this.", but instead does nothing. */
What am I doing wrong? This is plain javascript, but I am open to other libraries.
You need to use window[arg + "Info"] to get a value of global variable:
console.log(window[arg + "Info"]);
Here is a full fiddle
Use javascript function eval() , here's the doc
var firstInfo = "The first string says this.";
var secondInfo = "The second says that.";
function updateInfo(arg)
{
console.log( eval(arg + "Info") );
}
updateInfo("first");
It should be
updateInfo(arg)
{
firstInfo = arg + "Info";
console.log(firstInfo );
}
updateInfo(firstInfo );
Your "firstInfo" variable is defined in the global scope, and is hence attached to window object.
If you console it in the function scope without the window reference it will be invoked with the local scope.
Try this I have used the window object.
var firstInfo = "The first string says this.";
var secondInfo = "The second says that.";
function updateInfo(arg)
{
console.log(window[arg + "Info"]);
}
updateInfo("first");