So currently, my code works for inputs that contain one set of parentheses.
var re = /^.*\((.*\)).*$/;
var inPar = userIn.replace(re, '$1');
...meaning when the user enters the chemical formula Cu(NO3)2, alerting inPar returns NO3) , which I want.
However, if Cu(NO3)2(CO2)3 is the input, only CO2) is being returned.
I'm not too knowledgable in RegEx, so why is this happening, and is there a way I could put NO3) and CO2) into an array after they are found?
You want to use String.match instead of String.replace. You'll also want your regex to match multiple strings in parentheses, so you can't have ^ (start of string) and $ (end of string). And we can't be greedy when matching inside the parentheses, so we'll use .*?
Stepping through the changes, we get:
// Use Match
"Cu(NO3)2(CO2)3".match(/^.*\((.*\)).*$/);
["Cu(NO3)2(CO2)3", "CO2)"]
// Lets stop including the ) in our match
"Cu(NO3)2(CO2)3".match(/^.*\((.*)\).*$/);
["Cu(NO3)2(CO2)3", "CO2"]
// Instead of matching the entire string, lets search for just what we want
"Cu(NO3)2(CO2)3".match(/\((.*)\)/);
["(NO3)2(CO2)", "NO3)2(CO2"]
// Oops, we're being a bit too greedy, and capturing everything in a single match
"Cu(NO3)2(CO2)3".match(/\((.*?)\)/);
["(NO3)", "NO3"]
// Looks like we're only searching for a single result. Lets add the Global flag
"Cu(NO3)2(CO2)3".match(/\((.*?)\)/g);
["(NO3)", "(CO2)"]
// Global captures the entire match, and ignore our capture groups, so lets remove them
"Cu(NO3)2(CO2)3".match(/\(.*?\)/g);
["(NO3)", "(CO2)"]
// Now to remove the parentheses. We can use Array.prototype.map for that!
var elements = "Cu(NO3)2(CO2)3".match(/\(.*?\)/g);
elements = elements.map(function(match) { return match.slice(1, -1); })
["NO3", "CO2"]
// And if you want the closing parenthesis as Fabrício Matté mentioned
var elements = "Cu(NO3)2(CO2)3".match(/\(.*?\)/g);
elements = elements.map(function(match) { return match.substr(1); })
["NO3)", "CO2)"]
Your regex has anchors to match beginning and end of the string, so it won't suffice to match multiple occurrences. Updated code using String.match
with the RegExp g
flag (global modifier):
var userIn = 'Cu(NO3)2(CO2)3';
var inPar = userIn.match(/\([^)]*\)/g).map(function(s){ return s.substr(1); });
inPar; //["NO3)", "CO2)"]
In case you need old IE support: Array.prototype.map
polyfill
Or without polyfills:
var userIn = 'Cu(NO3)2(CO2)3';
var inPar = [];
userIn.replace(/\(([^)]*\))/g, function(s, m) { inPar.push(m); });
inPar; //["NO3)", "CO2)"]
Above matches a (
and captures a sequence of zero or more non-)
characters, followed by a )
and pushes it to the inPar
array.
The first regex does essentially the same, but uses the entire match including the opening (
parenthesis (which is later removed by mapping the array) instead of a capturing group.
From the question I assume the closing )
parenthesis is expected to be in the resulting strings, otherwise here are the updated solutions without the closing parenthesis:
For the first solution (using s.slice(1, -1)
):
var inPar = userIn.match(/\([^)]*\)/g).map(function(s){ return s.slice(1, -1);});
For the second solution (\)
outside of capturing group):
userIn.replace(/\(([^)]*)\)/g, function(s, m) { inPar.push(m); });
You could try the below:
"Cu(NO3)2".match(/(\S\S\d)/gi) // returns NO3
"Cu(NO3)2(CO2)3".match(/(\S\S\d)/gi) // returns NO3 CO2