Javascript - 正则表达式查找多个括号匹配

3

目前,我的代码适用于包含一个括号集的输入。

var re = /^.*\((.*\)).*$/;
var inPar = userIn.replace(re, '$1');

...这意味着当用户输入化学式Cu(NO3)2时,alerting inPar会返回NO3),这正是我想要的。

然而,如果输入的是Cu(NO3)2(CO2)3,则只返回CO2)。

我对RegEx不太熟悉,所以为什么会发生这种情况,有没有办法在找到它们后将NO3)和CO2)放入数组中?

3个回答

12
你需要使用String.match而不是String.replace。你还需要让你的正则表达式匹配多个括号内的字符串,所以你不能使用^(字符串开始)和$(字符串结束)。在括号内进行匹配时不能贪心,因此我们将使用.*?。
向下进行更改,我们得到:
// 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)"]

赶时间了。+1,因为指出匹配而不是替换和全局修饰符。 - Juan Guerrero
从问题来看,我认为期望在返回的字符串中包含闭合的 )。此外,我更喜欢使用 match.slice(1, -1) 来删除起始和结束括号,而不是将不必要的正则表达式放入其中。 - Fabrício Matté
好主意使用切片!我会更新代码来使用它。我不确定为什么Rygh2014想要那个“)”,但在你的代码和我的代码之间,这应该是一个相当明显的变化。 - SpenserJ
看起来不错。个人认为有点过多的代码和注释,直到达到令人满意的解决方案,但是+1是为了帮助OP理解它。 - Fabrício Matté

3

你的正则表达式有锚点来匹配字符串的开头和结尾,所以它不能满足匹配多个出现的要求。更新后的代码使用 String.match 和 RegExp g标志(全局修饰符):

var userIn = 'Cu(NO3)2(CO2)3';
var inPar = userIn.match(/\([^)]*\)/g).map(function(s){ return s.substr(1); });
inPar; //["NO3)", "CO2)"]

如果您需要支持旧版IE:

Array.prototype.map polyfill

或者不使用polyfills:

var userIn = 'Cu(NO3)2(CO2)3';
var inPar = [];
userIn.replace(/\(([^)]*\))/g, function(s, m) { inPar.push(m); });
inPar; //["NO3)", "CO2)"]

上面的匹配项是一个(,然后捕获零个或多个非)字符序列,接着是)并将其推送到inPar数组中。
第一个正则表达式基本上也是做同样的事情,但使用整个匹配项,包括开放的(括号(稍后通过映射数组删除),而不是捕获组。

根据问题,我认为期望在结果字符串中包含右括号),否则这里是没有右括号的更新解决方案:

对于第一个解决方案(使用s.slice(1, -1)):

var inPar = userIn.match(/\([^)]*\)/g).map(function(s){ return s.slice(1, -1);});

对于第二种解决方案(\)在捕获组之外):

userIn.replace(/\(([^)]*)\)/g, function(s, m) { inPar.push(m); });

0
你可以尝试以下代码:
"Cu(NO3)2".match(/(\S\S\d)/gi)   // returns NO3


"Cu(NO3)2(CO2)3".match(/(\S\S\d)/gi)   // returns NO3  CO2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接