Reputation: 135
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?
Upvotes: 3
Views: 10577
Reputation: 10619
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
Upvotes: 0
Reputation: 70139
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); });
Upvotes: 3
Reputation: 802
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)"]
Upvotes: 12