-1

I'm working on a regex pattern to match nested parentheses with exponential depth. While I have a working solution for shallow nesting, it fails when the nesting depth becomes very deep.

Here's my current regex pattern:

const regex = /\(([^()]+)\)/;
const text = "(((A))) (((((B))))) (((((((C)))))))";

const matches = text.match(regex);
console.log(matches);

In this example, I want to match the innermost content within the deepest set of parentheses, like "C". However, my current regex code only matches "A" and "B."

I'm looking for a regex pattern that can handle matching the innermost content within deeply nested parentheses like the "C" in the example. Any insights or corrections to my regex code would be greatly appreciated!

VLAZ
  • 26,331
  • 9
  • 49
  • 67
prabu naresh
  • 405
  • 1
  • 10
  • 2
    See [Regular expression to match balanced parentheses](https://stackoverflow.com/questions/546433/regular-expression-to-match-balanced-parentheses) – The fourth bird Sep 01 '23 at 11:38
  • If there is no stray opening/closing parentheses, `\(([^()]+)\)` would be sufficient. Otherwise, not possible. – InSync Sep 01 '23 at 11:42
  • 2
    Is there any reason why you specifically need to use a regex to achieve this? The problem is trivial to solve with a simple loop and a counter keeping track how "deep" you are nested. (Assuming from your question that you are only interested in the "deepest" match) – Jim Nilsson Sep 01 '23 at 11:59
  • As Jim says, if I the problem revolves around the use case scenario you brought, alone - another simple alternative would be `var result = text.replace(/\(|\)/g, '').split(' ')` – Veverke Sep 01 '23 at 14:24

2 Answers2

0

You forgot the global modifier, /g

const regex = /\(([^()]+)\)/g;
const text = "(((A))) (((((B))))) (((((((C)))))))";

const matches = text.match(regex);
console.log(matches);

You can avoid parenthesis in your capture result and the need for capture groups with a few lookarounds:

const regex = /(?<=\()[^()]+(?=\))/g;
const text = "(((A))) (((((B))))) (((((((C)))))))";

const matches = text.match(regex);
console.log(matches);

Depending on the complexity of your input, you could easily run into issues. For example, is the expectation that D, not C, gets matched? Whoops...

const regex = /(?<=\()[^()]+(?=\))/g;
const text = "(((A))) (((((B))))) (((((((C))(((((D))))))))))";

const matches = text.match(regex);
console.log(matches);
MonkeyZeus
  • 20,375
  • 4
  • 36
  • 77
0

Seems not possible with 1 regexp but you could match opening parentheses + content and check whether the closing parentheses match:

const text = "(((A))) (((((B))))) (((((((C))))))) ((((bad parentheses))((good ones))";

// captures opening parentheses + content
const regex = /(\(+)([^\)]+)/g;
const result = [];

let me;
while(m = regex.exec(text)){
  // check whether closing parentheses match
  const from = m.index + m[0].length;
  const closing = text.slice(from, from + m[1].length + 1);
  new RegExp('^\\){' + m[1].length + '}($|[^)])').test(closing) && result.push(m[2]);
}

console.log('captures:', ...result.map(JSON.stringify));
Alexander Nenashev
  • 8,775
  • 2
  • 6
  • 17