I need to parse strings intended for cross-spawn
From the following strings:
cmd foo bar
cmd "foo bar" --baz boom
cmd "baz \"boo\" bam"
cmd "foo 'bar bud' jim" jam
FOO=bar cmd baz
To an object:
{command: 'cmd', args: ['foo', 'bar']}
{command: 'cmd', args: ['foo bar', '--baz', 'boom']}
{command: 'cmd', args: ['baz "boo" bam']}
{command: 'cmd', args: ['foo \'bar bud\' jim', 'jam']}
{command: 'cmd', args: ['baz'], env: {FOO: 'bar'}}
I'm thinking a regex would be possible, but I'd love to avoid writing something custom. Anyone know of anything existing that could do this?
Edit
The question and answers are still valuable, but for my specific use-case I no longer need to do this. I'll use spawn-command instead (more accurately, I'll use spawn-command-with-kill) which doesn't require the command and args to be separate. This will make life much easier for me. Thanks!
You could roll your own with regex, but I'd strongly recommend looking at either:
minimist by Substack, or
yargs which is a more comprehensive implementation of argument parsing for node
Both are battle-hardened and well supported; minimist gets about 30 million downloads a month while yargs gets nearly half that.
It's very likely you can find a way to use one or the other to get the CLI syntax you want, with the exception of env support which IMO should be handled separately (I can't imagine why you'd want to be opinionated about environment variables being set as part of the command)
While you could use raw regular expressions, but what you're building is called a tokenizer. The reason you'd want a tokenizer is to handle certain contexts such as strings that contain spaces, which you don't want to split on.
There are existing generic libraries out there specifically designed for doing parsing and tokenization and can handle cases like strings, blocks, etc.
https://www.npmjs.com/package/js-parse
Additionally, most of these command line formats and config file formats already have parsers/tokenizers. You might want to leverage those and then normalize the results from each into your object structure.
A regular expression could match your command line...
^\s*(?:((?:(?:"(?:\\.|[^"])*")|(?:'[^']*')|(?:\\.)|\S)+)\s*)$
... but you wouldn't be able to extract individual words. Instead, you need to match the next word and accumulate it into a command line.
function parse_cmdline(cmdline) {
var re_next_arg = /^\s*((?:(?:"(?:\\.|[^"])*")|(?:'[^']*')|\\.|\S)+)\s*(.*)$/;
var next_arg = ['', '', cmdline];
var args = [];
while (next_arg = re_next_arg.exec(next_arg[2])) {
var quoted_arg = next_arg[1];
var unquoted_arg = "";
while (quoted_arg.length > 0) {
if (/^"/.test(quoted_arg)) {
var quoted_part = /^"((?:\\.|[^"])*)"(.*)$/.exec(quoted_arg);
unquoted_arg += quoted_part[1].replace(/\\(.)/g, "$1");
quoted_arg = quoted_part[2];
} else if (/^'/.test(quoted_arg)) {
var quoted_part = /^'([^']*)'(.*)$/.exec(quoted_arg);
unquoted_arg += quoted_part[1];
quoted_arg = quoted_part[2];
} else if (/^\\/.test(quoted_arg)) {
unquoted_arg += quoted_arg[1];
quoted_arg = quoted_arg.substring(2);
} else {
unquoted_arg += quoted_arg[0];
quoted_arg = quoted_arg.substring(1);
}
}
args[args.length] = unquoted_arg;
}
return args;
}
Related
I know in PHP we can do something like this:
$hello = "foo";
$my_string = "I pity the $hello";
Output: "I pity the foo"
I was wondering if this same thing is possible in JavaScript as well. Using variables inside strings without using concatenation — it looks more concise and elegant to write.
You can take advantage of Template Literals and use this syntax:
`String text ${expression}`
Template literals are enclosed by the back-tick (` `) (grave accent) instead of double or single quotes.
This feature has been introduced in ES2015 (ES6).
Example
var a = 5;
var b = 10;
console.log(`Fifteen is ${a + b}.`);
// "Fifteen is 15.
How neat is that?
Bonus:
It also allows for multi-line strings in javascript without escaping, which is great for templates:
return `
<div class="${foo}">
...
</div>
`;
Browser support:
As this syntax is not supported by older browsers (mostly Internet Explorer), you may want to use Babel/Webpack to transpile your code into ES5 to ensure it will run everywhere.
Side note:
Starting from IE8+ you can use basic string formatting inside console.log:
console.log('%s is %d.', 'Fifteen', 15);
// Fifteen is 15.
Prior to Firefox 34 / Chrome 41 / Safari 9 / Microsoft Edge, nope, that was not possible in javascript. You would have to resort to:
var hello = "foo";
var my_string = "I pity the " + hello;
Prior to Firefox 34 / Chrome 41 / Safari 9 / Microsoft Edge, no. Although you could try sprintf for JavaScript to get halfway there:
var hello = "foo";
var my_string = sprintf("I pity the %s", hello);
well you could do this, but it's not esp general
'I pity the $fool'.replace('$fool', 'fool')
You could easily write a function that does this intelligently if you really needed to
Complete and ready to be used answer for <ES6:
var Strings = {
create : (function() {
var regexp = /{([^{]+)}/g;
return function(str, o) {
return str.replace(regexp, function(ignore, key){
return (key = o[key]) == null ? '' : key;
});
}
})()
};
Call as
Strings.create("My firstname is {first}, my last name is {last}", {first:'Neo', last:'Andersson'});
To attach it to String.prototype:
String.prototype.create = function(o) {
return Strings.create(this, o);
}
Then use as :
"My firstname is ${first}".create({first:'Neo'});
If you are on >ES6 then you can also do:
let first = 'Neo';
`My firstname is ${first}`;
2022 update: Just use the ES6 Template Literals feature. It's fully supported in practically every browser you'll encounter these days. If you are still targeting browsers like IE11 and lower .. well, my heart goes out to you. The below solution I came up with 5 years ago will still work for you. Also, email me if you want a job that doesn't involve catering to old browsers 👍.
You can use this javascript function to do this sort of templating. No need to include an entire library.
function createStringFromTemplate(template, variables) {
return template.replace(new RegExp("\{([^\{]+)\}", "g"), function(_unused, varName){
return variables[varName];
});
}
createStringFromTemplate(
"I would like to receive email updates from {list_name} {var1} {var2} {var3}.",
{
list_name : "this store",
var1 : "FOO",
var2 : "BAR",
var3 : "BAZ"
}
);
Output: "I would like to receive email updates from this store FOO BAR BAZ."
Using a function as an argument to the String.replace() function was part of the ECMAScript v3 spec. See this SO answer for more details.
If you like to write CoffeeScript you could do:
hello = "foo"
my_string = "I pity the #{hello}"
CoffeeScript actually IS javascript, but with a much better syntax.
For an overview of CoffeeScript check this beginner's guide.
I would use the back-tick ``.
let name1 = 'Geoffrey';
let msg1 = `Hello ${name1}`;
console.log(msg1); // 'Hello Geoffrey'
But if you don't know name1 when you create msg1.
For exemple if msg1 came from an API.
You can use :
let name2 = 'Geoffrey';
let msg2 = 'Hello ${name2}';
console.log(msg2); // 'Hello ${name2}'
const regexp = /\${([^{]+)}/g;
let result = msg2.replace(regexp, function(ignore, key){
return eval(key);
});
console.log(result); // 'Hello Geoffrey'
It will replace ${name2} with his value.
I wrote this npm package stringinject https://www.npmjs.com/package/stringinject which allows you to do the following
var string = stringInject("this is a {0} string for {1}", ["test", "stringInject"]);
which will replace the {0} and {1} with the array items and return the following string
"this is a test string for stringInject"
or you could replace placeholders with object keys and values like so:
var str = stringInject("My username is {username} on {platform}", { username: "tjcafferkey", platform: "GitHub" });
"My username is tjcafferkey on Github"
If you're trying to do interpolation for microtemplating, I like Mustache.js for that purpose.
Don't see any external libraries mentioned here, but Lodash has _.template(),
https://lodash.com/docs/4.17.10#template
If you're already making use of the library it's worth checking out, and if you're not making use of Lodash you can always cherry pick methods from npm npm install lodash.template so you can cut down overhead.
Simplest form -
var compiled = _.template('hello <%= user %>!');
compiled({ 'user': 'fred' });
// => 'hello fred!'
There are a bunch of configuration options also -
_.templateSettings.interpolate = /{{([\s\S]+?)}}/g;
var compiled = _.template('hello {{ user }}!');
compiled({ 'user': 'mustache' });
// => 'hello mustache!'
I found custom delimiters most interesting.
Simply use:
var util = require('util');
var value = 15;
var s = util.format("The variable value is: %s", value)
Create a method similar to String.format() of Java
StringJoin=(s, r=[])=>{
r.map((v,i)=>{
s = s.replace('%'+(i+1),v)
})
return s
}
use
console.log(StringJoin('I can %1 a %2',['create','method'])) //output: 'I can create a method'
Peace quote of 2020:
Console.WriteLine("I {0} JavaScript!", ">:D<");
console.log(`I ${'>:D<'} C#`)
Maybe
wrt=(s, arr=[])=>{
arr.map((v,i)=>{s = s.replace(/\?/,v);});
return s;
};
a='first var';
b='secondvar';
tr=wrt('<tr><td>?<td></td>?</td><tr>',[a,b]);
console.log(tr);
//or use tr in html(tr), append(tr) so on and so forth
// Use ? with care in s
String.prototype.interpole = function () {
var c=0, txt=this;
while (txt.search(/{var}/g) > 0){
txt = txt.replace(/{var}/, arguments[c]);
c++;
}
return txt;
}
Uso:
var hello = "foo";
var my_string = "I pity the {var}".interpole(hello);
//resultado "I pity the foo"
var hello = "foo";
var my_string ="I pity the";
console.log(my_string, hello)
I know in PHP we can do something like this:
$hello = "foo";
$my_string = "I pity the $hello";
Output: "I pity the foo"
I was wondering if this same thing is possible in JavaScript as well. Using variables inside strings without using concatenation — it looks more concise and elegant to write.
You can take advantage of Template Literals and use this syntax:
`String text ${expression}`
Template literals are enclosed by the back-tick (` `) (grave accent) instead of double or single quotes.
This feature has been introduced in ES2015 (ES6).
Example
var a = 5;
var b = 10;
console.log(`Fifteen is ${a + b}.`);
// "Fifteen is 15.
How neat is that?
Bonus:
It also allows for multi-line strings in javascript without escaping, which is great for templates:
return `
<div class="${foo}">
...
</div>
`;
Browser support:
As this syntax is not supported by older browsers (mostly Internet Explorer), you may want to use Babel/Webpack to transpile your code into ES5 to ensure it will run everywhere.
Side note:
Starting from IE8+ you can use basic string formatting inside console.log:
console.log('%s is %d.', 'Fifteen', 15);
// Fifteen is 15.
Prior to Firefox 34 / Chrome 41 / Safari 9 / Microsoft Edge, nope, that was not possible in javascript. You would have to resort to:
var hello = "foo";
var my_string = "I pity the " + hello;
Prior to Firefox 34 / Chrome 41 / Safari 9 / Microsoft Edge, no. Although you could try sprintf for JavaScript to get halfway there:
var hello = "foo";
var my_string = sprintf("I pity the %s", hello);
well you could do this, but it's not esp general
'I pity the $fool'.replace('$fool', 'fool')
You could easily write a function that does this intelligently if you really needed to
Complete and ready to be used answer for <ES6:
var Strings = {
create : (function() {
var regexp = /{([^{]+)}/g;
return function(str, o) {
return str.replace(regexp, function(ignore, key){
return (key = o[key]) == null ? '' : key;
});
}
})()
};
Call as
Strings.create("My firstname is {first}, my last name is {last}", {first:'Neo', last:'Andersson'});
To attach it to String.prototype:
String.prototype.create = function(o) {
return Strings.create(this, o);
}
Then use as :
"My firstname is ${first}".create({first:'Neo'});
If you are on >ES6 then you can also do:
let first = 'Neo';
`My firstname is ${first}`;
2022 update: Just use the ES6 Template Literals feature. It's fully supported in practically every browser you'll encounter these days. If you are still targeting browsers like IE11 and lower .. well, my heart goes out to you. The below solution I came up with 5 years ago will still work for you. Also, email me if you want a job that doesn't involve catering to old browsers 👍.
You can use this javascript function to do this sort of templating. No need to include an entire library.
function createStringFromTemplate(template, variables) {
return template.replace(new RegExp("\{([^\{]+)\}", "g"), function(_unused, varName){
return variables[varName];
});
}
createStringFromTemplate(
"I would like to receive email updates from {list_name} {var1} {var2} {var3}.",
{
list_name : "this store",
var1 : "FOO",
var2 : "BAR",
var3 : "BAZ"
}
);
Output: "I would like to receive email updates from this store FOO BAR BAZ."
Using a function as an argument to the String.replace() function was part of the ECMAScript v3 spec. See this SO answer for more details.
If you like to write CoffeeScript you could do:
hello = "foo"
my_string = "I pity the #{hello}"
CoffeeScript actually IS javascript, but with a much better syntax.
For an overview of CoffeeScript check this beginner's guide.
I would use the back-tick ``.
let name1 = 'Geoffrey';
let msg1 = `Hello ${name1}`;
console.log(msg1); // 'Hello Geoffrey'
But if you don't know name1 when you create msg1.
For exemple if msg1 came from an API.
You can use :
let name2 = 'Geoffrey';
let msg2 = 'Hello ${name2}';
console.log(msg2); // 'Hello ${name2}'
const regexp = /\${([^{]+)}/g;
let result = msg2.replace(regexp, function(ignore, key){
return eval(key);
});
console.log(result); // 'Hello Geoffrey'
It will replace ${name2} with his value.
I wrote this npm package stringinject https://www.npmjs.com/package/stringinject which allows you to do the following
var string = stringInject("this is a {0} string for {1}", ["test", "stringInject"]);
which will replace the {0} and {1} with the array items and return the following string
"this is a test string for stringInject"
or you could replace placeholders with object keys and values like so:
var str = stringInject("My username is {username} on {platform}", { username: "tjcafferkey", platform: "GitHub" });
"My username is tjcafferkey on Github"
If you're trying to do interpolation for microtemplating, I like Mustache.js for that purpose.
Don't see any external libraries mentioned here, but Lodash has _.template(),
https://lodash.com/docs/4.17.10#template
If you're already making use of the library it's worth checking out, and if you're not making use of Lodash you can always cherry pick methods from npm npm install lodash.template so you can cut down overhead.
Simplest form -
var compiled = _.template('hello <%= user %>!');
compiled({ 'user': 'fred' });
// => 'hello fred!'
There are a bunch of configuration options also -
_.templateSettings.interpolate = /{{([\s\S]+?)}}/g;
var compiled = _.template('hello {{ user }}!');
compiled({ 'user': 'mustache' });
// => 'hello mustache!'
I found custom delimiters most interesting.
Simply use:
var util = require('util');
var value = 15;
var s = util.format("The variable value is: %s", value)
Create a method similar to String.format() of Java
StringJoin=(s, r=[])=>{
r.map((v,i)=>{
s = s.replace('%'+(i+1),v)
})
return s
}
use
console.log(StringJoin('I can %1 a %2',['create','method'])) //output: 'I can create a method'
Peace quote of 2020:
Console.WriteLine("I {0} JavaScript!", ">:D<");
console.log(`I ${'>:D<'} C#`)
Maybe
wrt=(s, arr=[])=>{
arr.map((v,i)=>{s = s.replace(/\?/,v);});
return s;
};
a='first var';
b='secondvar';
tr=wrt('<tr><td>?<td></td>?</td><tr>',[a,b]);
console.log(tr);
//or use tr in html(tr), append(tr) so on and so forth
// Use ? with care in s
String.prototype.interpole = function () {
var c=0, txt=this;
while (txt.search(/{var}/g) > 0){
txt = txt.replace(/{var}/, arguments[c]);
c++;
}
return txt;
}
Uso:
var hello = "foo";
var my_string = "I pity the {var}".interpole(hello);
//resultado "I pity the foo"
var hello = "foo";
var my_string ="I pity the";
console.log(my_string, hello)
I'm currently coding a Command Line program for function isPunct in Javascript and struggling to both start & completely finish it. Here's what I have so far:
function isPunct(str) {
var str = ".,:!?;";
if (/\pPunct/.test(str)) {
alert("Character is punctuation")
}
else {
alert("Character is not punctuation")
}
}
It's going through the console just fine, but isn't actually picking out the punctuation. Please help if you can! And thanks in advance.
function isPunct() {
//var str = "a.,:!?;"; -> false because of a
var str = ".,:!?;";
if (/^(\.|\,|\!|\?|\:|\;|\"|\'|\-|\(|\))*$/g.test(str)) {
alert("Character is punctuation")
}
else {
alert("Character is not punctuation")
}
}
isPunct();
It looks as if you were attempting to use Unicode property escapes (\p{UnicodePropertyName=UnicodePropertyValue}), which are not currently a part of the JavaScript standard. There is a proposal to add this functionality, but it has thus far only reached stage 2 of the TC39 process.
However, Mathias Bynens has created a wonderful tool called regexpu that will transpile these property escapes to their standard equivalents. I doubt all of the codepoints in the result are necessary to you, so feel free to shorten the list of characters as you see fit.
(Permalink to the ES5 equivalent of /^\p{Punctuation}*$/u.)
var onlyPunctuation = /^(?:[!-#%-\*,-/:;\?#\[-\]_\{\}\xA1\xA7\xAB\xB6\xB7\xBB\xBF\u037E\u0387\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u0AF0\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F14\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1360-\u1368\u1400\u166D\u166E\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CC0-\u1CC7\u1CD3\u2010-\u2027\u2030-\u2043\u2045-\u2051\u2053-\u205E\u207D\u207E\u208D\u208E\u2308-\u230B\u2329\u232A\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30-\u2E44\u3001-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA8FC\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uAAF0\uAAF1\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F\uFF5B\uFF5D\uFF5F-\uFF65]|\uD800[\uDD00-\uDD02\uDF9F\uDFD0]|\uD801\uDD6F|\uD802[\uDC57\uDD1F\uDD3F\uDE50-\uDE58\uDE7F\uDEF0-\uDEF6\uDF39-\uDF3F\uDF99-\uDF9C]|\uD804[\uDC47-\uDC4D\uDCBB\uDCBC\uDCBE-\uDCC1\uDD40-\uDD43\uDD74\uDD75\uDDC5-\uDDC9\uDDCD\uDDDB\uDDDD-\uDDDF\uDE38-\uDE3D\uDEA9]|\uD805[\uDC4B-\uDC4F\uDC5B\uDC5D\uDCC6\uDDC1-\uDDD7\uDE41-\uDE43\uDE60-\uDE6C\uDF3C-\uDF3E]|\uD807[\uDC41-\uDC45\uDC70\uDC71]|\uD809[\uDC70-\uDC74]|\uD81A[\uDE6E\uDE6F\uDEF5\uDF37-\uDF3B\uDF44]|\uD82F\uDC9F|\uD836[\uDE87-\uDE8B]|\uD83A[\uDD5E\uDD5F])*$/
function isPunct (string) {
return onlyPunctuation.test(string)
}
console.log(isPunct('.,:!?;')) //=> true
console.log(isPunct('letters')) //=> false
I want to carry out variable substitutions on a string (I've already ruled out template literals because the string has to be stored and evaluated later).
Mustache or something like it would seem like a contender, but I want to know if the substitution was incomplete. In this case, it's to produce urls, so missing parts mean invalid urls:
Testing this out in node:
var Mustache = require('mustache');
var result = Mustache.render("/someurl/{{path1}}/{{path2}}/", {path1:"my-path-to-1"})
console.log(`result:${result}:`)
This happens without a problem, but the resulting url is useless because Mustache silently replaced the missing path2 with an empty string. What I would like to see is an exception getting thrown (best) or failing that an easy way to recognize that not everything was substituted.
Note: the template string is arbitrary and so are the substitution object's contents.
output:
result:/someurl/my-path-to-1//:
This is the Python equivalent that I am looking for:
res = "/someurl/%(path1)s/%(path2)s/" % {"path1":"my-path-to-1"}
output:
KeyError: 'path2'
I ended up using sprintf, which has the benefit of having a different format than Mustache (or Django) so that you can embed it in data-url or the like:
const sprintf = require("sprintf-js").sprintf;
var o_substit = {
path1 : "mypath1"
};
var T_URL = "/someurl/%(path1)s/%(path2)s/";
console.log(`\nT_URL:${T_URL}, substitutions:`);
try {
console.dir(o_substit);
console.log("expecting a failure...")
var url = sprintf(T_URL, o_substit);
console.log(` url:${url}:`);
}
catch (e){
console.log(` exception:${e}`);
};
var o_substit = {
path1 : "mypath1"
,path2 : "mypath2"
};
console.log(`\nT_URL:${T_URL}, substitutions:`);
try{
console.dir(o_substit);
console.log("\nexpecting a success:")
var url = sprintf(T_URL, o_substit);
console.log(` url:${url}:`);
}
catch (e){
console.log(` exception:${e}`);
};
output:
T_URL:/someurl/%(path1)s/%(path2)s/, substitutions:
{ path1: 'mypath1' }
expecting a failure...
exception:Error: [sprintf] property 'path2' does not exist
T_URL:/someurl/%(path1)s/%(path2)s/, substitutions:
{ path1: 'mypath1', path2: 'mypath2' }
expecting a success:
url:/someurl/mypath1/mypath2/:
I know in PHP we can do something like this:
$hello = "foo";
$my_string = "I pity the $hello";
Output: "I pity the foo"
I was wondering if this same thing is possible in JavaScript as well. Using variables inside strings without using concatenation — it looks more concise and elegant to write.
You can take advantage of Template Literals and use this syntax:
`String text ${expression}`
Template literals are enclosed by the back-tick (` `) (grave accent) instead of double or single quotes.
This feature has been introduced in ES2015 (ES6).
Example
var a = 5;
var b = 10;
console.log(`Fifteen is ${a + b}.`);
// "Fifteen is 15.
How neat is that?
Bonus:
It also allows for multi-line strings in javascript without escaping, which is great for templates:
return `
<div class="${foo}">
...
</div>
`;
Browser support:
As this syntax is not supported by older browsers (mostly Internet Explorer), you may want to use Babel/Webpack to transpile your code into ES5 to ensure it will run everywhere.
Side note:
Starting from IE8+ you can use basic string formatting inside console.log:
console.log('%s is %d.', 'Fifteen', 15);
// Fifteen is 15.
Prior to Firefox 34 / Chrome 41 / Safari 9 / Microsoft Edge, nope, that was not possible in javascript. You would have to resort to:
var hello = "foo";
var my_string = "I pity the " + hello;
Prior to Firefox 34 / Chrome 41 / Safari 9 / Microsoft Edge, no. Although you could try sprintf for JavaScript to get halfway there:
var hello = "foo";
var my_string = sprintf("I pity the %s", hello);
well you could do this, but it's not esp general
'I pity the $fool'.replace('$fool', 'fool')
You could easily write a function that does this intelligently if you really needed to
Complete and ready to be used answer for <ES6:
var Strings = {
create : (function() {
var regexp = /{([^{]+)}/g;
return function(str, o) {
return str.replace(regexp, function(ignore, key){
return (key = o[key]) == null ? '' : key;
});
}
})()
};
Call as
Strings.create("My firstname is {first}, my last name is {last}", {first:'Neo', last:'Andersson'});
To attach it to String.prototype:
String.prototype.create = function(o) {
return Strings.create(this, o);
}
Then use as :
"My firstname is ${first}".create({first:'Neo'});
If you are on >ES6 then you can also do:
let first = 'Neo';
`My firstname is ${first}`;
2022 update: Just use the ES6 Template Literals feature. It's fully supported in practically every browser you'll encounter these days. If you are still targeting browsers like IE11 and lower .. well, my heart goes out to you. The below solution I came up with 5 years ago will still work for you. Also, email me if you want a job that doesn't involve catering to old browsers 👍.
You can use this javascript function to do this sort of templating. No need to include an entire library.
function createStringFromTemplate(template, variables) {
return template.replace(new RegExp("\{([^\{]+)\}", "g"), function(_unused, varName){
return variables[varName];
});
}
createStringFromTemplate(
"I would like to receive email updates from {list_name} {var1} {var2} {var3}.",
{
list_name : "this store",
var1 : "FOO",
var2 : "BAR",
var3 : "BAZ"
}
);
Output: "I would like to receive email updates from this store FOO BAR BAZ."
Using a function as an argument to the String.replace() function was part of the ECMAScript v3 spec. See this SO answer for more details.
If you like to write CoffeeScript you could do:
hello = "foo"
my_string = "I pity the #{hello}"
CoffeeScript actually IS javascript, but with a much better syntax.
For an overview of CoffeeScript check this beginner's guide.
I would use the back-tick ``.
let name1 = 'Geoffrey';
let msg1 = `Hello ${name1}`;
console.log(msg1); // 'Hello Geoffrey'
But if you don't know name1 when you create msg1.
For exemple if msg1 came from an API.
You can use :
let name2 = 'Geoffrey';
let msg2 = 'Hello ${name2}';
console.log(msg2); // 'Hello ${name2}'
const regexp = /\${([^{]+)}/g;
let result = msg2.replace(regexp, function(ignore, key){
return eval(key);
});
console.log(result); // 'Hello Geoffrey'
It will replace ${name2} with his value.
I wrote this npm package stringinject https://www.npmjs.com/package/stringinject which allows you to do the following
var string = stringInject("this is a {0} string for {1}", ["test", "stringInject"]);
which will replace the {0} and {1} with the array items and return the following string
"this is a test string for stringInject"
or you could replace placeholders with object keys and values like so:
var str = stringInject("My username is {username} on {platform}", { username: "tjcafferkey", platform: "GitHub" });
"My username is tjcafferkey on Github"
If you're trying to do interpolation for microtemplating, I like Mustache.js for that purpose.
Don't see any external libraries mentioned here, but Lodash has _.template(),
https://lodash.com/docs/4.17.10#template
If you're already making use of the library it's worth checking out, and if you're not making use of Lodash you can always cherry pick methods from npm npm install lodash.template so you can cut down overhead.
Simplest form -
var compiled = _.template('hello <%= user %>!');
compiled({ 'user': 'fred' });
// => 'hello fred!'
There are a bunch of configuration options also -
_.templateSettings.interpolate = /{{([\s\S]+?)}}/g;
var compiled = _.template('hello {{ user }}!');
compiled({ 'user': 'mustache' });
// => 'hello mustache!'
I found custom delimiters most interesting.
Simply use:
var util = require('util');
var value = 15;
var s = util.format("The variable value is: %s", value)
Create a method similar to String.format() of Java
StringJoin=(s, r=[])=>{
r.map((v,i)=>{
s = s.replace('%'+(i+1),v)
})
return s
}
use
console.log(StringJoin('I can %1 a %2',['create','method'])) //output: 'I can create a method'
Peace quote of 2020:
Console.WriteLine("I {0} JavaScript!", ">:D<");
console.log(`I ${'>:D<'} C#`)
Maybe
wrt=(s, arr=[])=>{
arr.map((v,i)=>{s = s.replace(/\?/,v);});
return s;
};
a='first var';
b='secondvar';
tr=wrt('<tr><td>?<td></td>?</td><tr>',[a,b]);
console.log(tr);
//or use tr in html(tr), append(tr) so on and so forth
// Use ? with care in s
String.prototype.interpole = function () {
var c=0, txt=this;
while (txt.search(/{var}/g) > 0){
txt = txt.replace(/{var}/, arguments[c]);
c++;
}
return txt;
}
Uso:
var hello = "foo";
var my_string = "I pity the {var}".interpole(hello);
//resultado "I pity the foo"
var hello = "foo";
var my_string ="I pity the";
console.log(my_string, hello)