417

I need a regular expression to select all the text between two outer brackets.

Example:
START_TEXT(text here(possible text)text(possible text(more text)))END_TXT
^ ^

Result:
(text here(possible text)text(possible text(more text)))

Ahmed Nabil
  • 17,392
  • 11
  • 61
  • 88
DaveF
  • 6,529
  • 6
  • 25
  • 20
  • 6
    This question is very poor because it's not clear what it's is asking. All of the answers interpreted it differently. @DaveF can you please clarify the question? – Matt Fenwick Dec 17 '12 at 18:25
  • 2
    Answered in this post: http://stackoverflow.com/questions/6331065/matching-balanced-parenthesis-in-ruby-using-recursive-regular-expressions-like-p – sship21 Dec 06 '13 at 22:47

21 Answers21

260

I want to add this answer for quickreference. Feel free to update.


.NET Regex using balancing groups:

\((?>\((?<c>)|[^()]+|\)(?<-c>))*(?(c)(?!))\)

Where c is used as the depth counter.

Demo at Regexstorm.com


PCRE using a recursive pattern:

\((?:[^)(]+|(?R))*+\)

Demo at regex101; Or without alternation:

\((?:[^)(]*(?R)?)*+\)

Demo at regex101; Or unrolled for performance:

\([^)(]*+(?:(?R)[^)(]*)*+\)

Demo at regex101; The pattern is pasted at (?R) which represents (?0).

Perl, PHP, Notepad++, R: perl=TRUE, Python: PyPI regex module with (?V1) for Perl behaviour.
(the new version of PyPI regex package already defaults to this → DEFAULT_VERSION = VERSION1)


Ruby using subexpression calls:

With Ruby 2.0 \g<0> can be used to call full pattern.

\((?>[^)(]+|\g<0>)*\)

Demo at Rubular; Ruby 1.9 only supports capturing group recursion:

(\((?>[^)(]+|\g<1>)*\))

Demo at Rubular  (atomic grouping since Ruby 1.9.3)


JavaScript  API :: XRegExp.matchRecursive

XRegExp.matchRecursive(str, '\\(', '\\)', 'g');

Java: An interesting idea using forward references by @jaytea.


Without recursion up to 3 levels of nesting:
(JS, Java and other regex flavors)

To prevent runaway if unbalanced, with * on innermost [)(] only.

\((?:[^)(]|\((?:[^)(]|\((?:[^)(]|\([^)(]*\))*\))*\))*\)

Demo at regex101; Or unrolled for better performance (preferred).

\([^)(]*(?:\([^)(]*(?:\([^)(]*(?:\([^)(]*\)[^)(]*)*\)[^)(]*)*\)[^)(]*)*\)

Demo at regex101; Deeper nesting needs to be added as required.

// JS-Snippet to generate pattern
function generatePattern()
{
  // Set max depth & pattern type
  let d = document.getElementById("maxDepth").value;
  let t = document.getElementById("patternType").value;
  
  // Pattern variants: 0=default, 1=unrolled (more efficient)
  let p = [['\\((?:[^)(]|',')*\\)'], ['\\([^)(]*(?:','[^)(]*)*\\)']];
  
  // Generate and display the pattern
  console.log(p[t][0].repeat(d) + '\\([^)(]*\\)' + p[t][1].repeat(d));
} generatePattern();
Max depth = <input type="text" id="maxDepth" size="1" value="3"> 
<select id="patternType" onchange="generatePattern()">
  <option value="0">default pattern</option>
  <option value="1" selected>unrolled pattern</option>
</select>
<input type="submit" onclick="generatePattern()" value="generate!">

Reference - What does this regex mean?

bobble bubble
  • 16,888
  • 3
  • 27
  • 46
  • 1
    When you repeat a group with a possessive quantifier, it's useless to make that group atomic since all backtracking positions in that group are deleted at each repetition. So writing `(?>[^)(]+|(?R))*+` is the same than writing `(?:[^)(]+|(?R))*+`. Same thing for the next pattern. About the unrolled version, you can put a possessive quantifier here: `[^)(]*+` to prevent backtracking (in case there's no closing bracket). – Casimir et Hippolyte Jun 24 '19 at 21:03
  • About the Ruby 1.9 pattern, instead of making the repeated group atomic (that has a limited interest when there are many nested parenthesis `(...(..)..(..)..(..)..(..)..)`) in the subject string), you can use a simple non-capturing group and enclose all in an atomic group: `(?>(?:[^)(]+|\g<1>)*)` (this behaves exactly like a possessive quantifier). In Ruby 2.x, the possessive quantifier is available. – Casimir et Hippolyte Jun 24 '19 at 21:13
  • 1
    @CasimiretHippolyte Thank you! I adjusted the PCRE patterns and for Ruby 1.9, do you mean the whole pattern to be [like this](https://rubular.com/r/ioj4C7KwN3UsOs)? Please feel free to update yourself. I understand what you mean, but not sure if there is much improvement. – bobble bubble Jun 25 '19 at 09:13
  • Thanks for the JavaScript example that doesn't use recursion. I was able to use this in vbScript which has similar limitations. – Ben Sep 09 '20 at 01:33
  • Thank you, this answer is amazing, all the effort with possible demos allowed me to pick the one I use (regex101.org). I'm very grateful for your work – Tomas Votruba Sep 13 '20 at 17:20
  • you might want this in combination with other strings as well, for example: if \(youWantToLookForEnclosingBrackets\) (?{([^{}]|(?&brackets))*}) (https://regex101.com/r/pDvixX/1) – dfinki Apr 27 '21 at 14:15
  • 1
    In case anyone needs a curly bracket version of this for .NET: `\{(?>\{(?)|[^{}]+|\}(?<-c>))*(?(c)(?!))\}` – MgSam Jul 20 '21 at 19:08
  • 3
    For the recursion, instead of `\((?:[^)(]+|(?R))*+\)` I would recommend `(\((?:[^)(]+|(?1))*+\))` (or `?2`, `?3`, etc, depending on what number group it is). `?R` always recurses back to the very beginning of the expression. Which, if you're using this alone, is fine. But for example, if you're finding logical comparisons following an `if` statement `if \((?:[^)(]+|(?R))*+\)` won't match anything because the `if` would also have to be repeated to match, not just the parentheses. `if (\((?:[^)(]+|(?1))*+\))` however, will only check for `if` once and then recursively check the first group. – Trashman Apr 25 '22 at 20:52
  • Hey @Trashman, thanks for your comment! Yes, the php samples which I put, are for the full pattern `(?0)` else if you need to use this inside like you said, recurse the desired group. – bobble bubble Apr 25 '22 at 21:21
  • Thanks @bobblebubble Unfortunately, I just found an issue with my previous comment. If you're trying to reference the group inside the parentheses in a replacement using $1, $2, etc, the numbers keep going up based on the nesting, making them basically unusable. To combat that, I had to put the recursion inside another group and put that inside a branch reset group, so the (hopefully) final expression is: `(\s[^#]if) ((?|\(([^)(]+|(?2))*+\)))([^{;]*);` and then for replacement you would use something like `$1 $2{$4;}`. `$3` will change with each recursion, but `$2` will retain all of it. – Trashman Apr 25 '22 at 21:46
  • Hey @Trashman I see. Depending on the requirements, I would also think of using *non-capturing groups* or even an *atomic group* which is also non-capuring and drop the possessive quantifier. Could imagine something like [`(\s[^#]if) (\((?>[^)(]+|(?2))*\))([^{;]*);`](https://regex101.com/r/YBPEix/1) if you need all 3 captures or just [`\s[^#]if (\((?>[^)(]+|(?1))*\))[^{;]*;`](https://regex101.com/r/YBPEix/2) or without capturing the parenthesis: [`\s[^#]if (\(((?>[^)(]+|(?1))*)\))[^{;]*;`](https://regex101.com/r/iacBCz/1) well, many ideas :) – bobble bubble Apr 26 '22 at 12:14
  • 1
    @bobblebubble good point. Why capture the 3rd group at all if I throw it out? There's always many ways to skin the same cat with RegEx. – Trashman Apr 27 '22 at 14:55
  • 1
    I had been using this PCRE solution using ?R but found it does not work with (*SKIP)(*FAIL) where the ?1 method by [@Manish](https://stackoverflow.com/a/62363958/1898524) does. I created an example here: https://regex101.com/r/xkVzVP/1 – Ben Sep 29 '22 at 15:14
  • Javascript example fails for this string: `3+(5+((2+3-(5))+1))+3` – Albert Renshaw Oct 27 '22 at 01:34
  • @AlbertRenshaw Your string is three levels deep nested, this was only for max two... I just reworked this section to support max 3 levels. See [this demo at regex101](https://regex101.com/r/ucJ05p/2). – bobble bubble Nov 25 '22 at 14:47
  • How do you capture the match itself? I've tried replacing the outermost non-capturing group to a capturing one, I will match the smallest parentheses substring: https://regex101.com/r/VA17kk/1 – Ricola Apr 04 '23 at 13:50
  • 1
    @Ricola You can just wrap it into a capturing group: [`(\((?:[^)(]+|(?R))*+\))`](https://regex101.com/r/ft26yE/1) – bobble bubble Apr 05 '23 at 18:26
177

Regular expressions are the wrong tool for the job because you are dealing with nested structures, i.e. recursion.

But there is a simple algorithm to do this, which I described in more detail in this answer to a previous question. The gist is to write code which scans through the string keeping a counter of the open parentheses which have not yet been matched by a closing parenthesis. When that counter returns to zero, then you know you've reached the final closing parenthesis.

Makyen
  • 31,849
  • 12
  • 86
  • 121
Frank
  • 64,140
  • 93
  • 237
  • 324
  • I was toying with this idea but thought I might be able to do it with RegExp. Will go back to my original plan. Thanks everyone – DaveF Feb 13 '09 at 16:25
  • 22
    .NET's implementation has [Balancing Group Definitions http://msdn.microsoft.com/en-us/library/bs2twtah.aspx#balancing_group_definition] which allow this sort of thing. – Carl G Jun 13 '10 at 04:08
  • 48
    I disagree that regular expressions are the wrong tool for this for a few reasons. 1) Most regular expression implementations have a workable if not perfect solution for this. 2) Often you are trying to find balanced pairs of delimiters in a context where other criteria well suited to regular expressions are also in play. 3) Often you are handing a regular expression into some API that only accepts regular expressions and you have no choice. – Kenneth Baltrinic May 02 '14 at 03:31
  • 1
    Here's a [Javascript implementation of Frank's algorithm](http://stackoverflow.com/a/27088184/1049693) – pilau Nov 23 '14 at 11:00
  • 39
    Regex is the RIGHT tool for the job. This answer is not right. See rogal111's answer. – Andrew Dec 26 '15 at 02:48
  • 1
    Regex recursion certainly can and should be used in this scenario. – Phil Tune Mar 07 '16 at 20:28
  • 11
    Absolutely agree with the answer. Although there are some implementations of recursion in regexp, they are equal to finite-state machines and are not supposted to work with nested structures, but Context Free Grammars do this. Look at Homsky's hierarcy of Formal Grammars. – Nick Roz Apr 20 '16 at 10:52
  • 4
    Frank is right, Context free grammars cannot be described by regular expressions. That's the key point to this answer. – juliccr Jul 18 '17 at 22:07
  • 3
    Language purists are correctly arguing that a Chomsky `regular` language specifically precludes recursion. That doesn't mean that regexps have to be regular. Sure, the label is kinda wrong, but the syntax of the language is good enough to let people completely address use cases which are otherwise 90% solved by the truly regular subset of modern regexps. – ericP Aug 19 '21 at 04:23
142

You can use regex recursion:

\(([^()]|(?R))*\)
Amal Murali
  • 75,622
  • 18
  • 128
  • 150
rogal111
  • 5,874
  • 2
  • 27
  • 33
  • 5
    An example would be really useful here, I can't get this to work for things like "(1, (2, 3)) (4, 5)". – Andy Hayden Oct 15 '14 at 00:01
  • 5
    @AndyHayden this is because "(1, (2, 3)) (4, 5)" has two groups separated with space. Use my regexp with global flag: /\(([^()]|(?R))*\)/g. Here is online test: http://regex101.com/r/lF0fI1/1 – rogal111 Oct 23 '14 at 09:45
  • 1
    I asked a question about this last week http://stackoverflow.com/questions/26385984/recursive-pattern-in-regex – Andy Hayden Oct 23 '14 at 17:20
  • 7
    In .NET 4.5 I get the following error for this pattern: `Unrecognized grouping construct`. – nam Jun 28 '15 at 00:16
  • 4
    Awesome! This is a great feature of regex. Thank you for being the only one to actually answer the question. Also, that regex101 site is sweet. – Andrew Dec 26 '15 at 02:47
  • Very nice answer. Notepad++ 6.8.8 supports this. – bers Feb 15 '16 at 21:44
  • How would your expression with global flag (the one you gave an online test) be used with c++ ???? I am trying to break a string up into chunks in respect to their parenthesis. – Jared Smith Apr 08 '16 at 03:19
  • 1
    @nam You need [PCRE](https://github.com/ltrzesniewski/pcre-net) to be able to use the recursive feature in this expression. A more detailed explanation [here](http://stackoverflow.com/questions/34492949/c-sharp-and-regex-unrecognized-grouping-construct). – jsirr13 Nov 14 '16 at 22:45
  • Good answer - This regex is made vastly more efficient by changing it to: `\(([^()]+|(?R))*\)` – Addison Nov 02 '18 at 03:24
  • 2
    As a side note, this is kind of misnamed because [a real regex isn't recursive](https://en.wikipedia.org/wiki/Chomsky_hierarchy). – EJoshuaS - Stand with Ukraine Dec 12 '18 at 14:19
  • No, [bobblebubble's answer](https://stackoverflow.com/a/35271017/3832970) is the best and the PCRE regex to match nested parentheses given there is more efficient. – Wiktor Stribiżew Jun 14 '19 at 17:10
  • I had been using this PCRE solution using ?R but found it does not work with (*SKIP)(*FAIL) where the ?1 method by [@Manish](https://stackoverflow.com/a/62363958/1898524) does. I created an example here: https://regex101.com/r/xkVzVP/1 – Ben Sep 29 '22 at 15:15
33
[^\(]*(\(.*\))[^\)]*

[^\(]* matches everything that isn't an opening bracket at the beginning of the string, (\(.*\)) captures the required substring enclosed in brackets, and [^\)]* matches everything that isn't a closing bracket at the end of the string. Note that this expression does not attempt to match brackets; a simple parser (see dehmann's answer) would be more suitable for that.

Community
  • 1
  • 1
Zach Scrivena
  • 29,073
  • 11
  • 63
  • 73
25

This answer explains the theoretical limitation of why regular expressions are not the right tool for this task.


Regular expressions can not do this.

Regular expressions are based on a computing model known as Finite State Automata (FSA). As the name indicates, a FSA can remember only the current state, it has no information about the previous states.

FSA

In the above diagram, S1 and S2 are two states where S1 is the starting and final step. So if we try with the string 0110 , the transition goes as follows:

      0     1     1     0
-> S1 -> S2 -> S2 -> S2 ->S1

In the above steps, when we are at second S2 i.e. after parsing 01 of 0110, the FSA has no information about the previous 0 in 01 as it can only remember the current state and the next input symbol.

In the above problem, we need to know the no of opening parenthesis; this means it has to be stored at some place. But since FSAs can not do that, a regular expression can not be written.

However, an algorithm can be written to do this task. Algorithms are generally falls under Pushdown Automata (PDA). PDA is one level above of FSA. PDA has an additional stack to store some additional information. PDAs can be used to solve the above problem, because we can 'push' the opening parenthesis in the stack and 'pop' them once we encounter a closing parenthesis. If at the end, stack is empty, then opening parenthesis and closing parenthesis matches. Otherwise not.

Somnath Musib
  • 3,548
  • 3
  • 34
  • 47
  • Push and pop are possible in regexp https://stackoverflow.com/questions/17003799/what-are-regular-expression-balancing-groups https://www.regular-expressions.info/balancing.html – Marco Aug 23 '18 at 19:35
  • 3
    There are several answers here, which prooves, it IS possible. – Jiří Herník Sep 20 '18 at 10:48
  • 6
    @Marco This answer talks about regular expressions in theoretical perspective. Many regex engines now a days does not only rely on this theoretical model and uses some additional memory to do the job! – Somnath Musib Jun 03 '19 at 02:07
  • 8
    @JiříHerník: those are not regular expressions in the strict sense: not defined as regular expressions by *Kleene*. Some regular expression engines indeed have implemented some extra capabilities, making them parse more than only *regular languages*. – Willem Van Onsem Jun 10 '19 at 21:27
  • 1
    This one should be an accepted answer. Unfortunately many "developers" do not have a proper Comp Sc/Eng education and unaware of such topics as Halting problem, Pumping lemma, etc... – fade2black May 13 '22 at 23:00
23
(?<=\().*(?=\))

If you want to select text between two matching parentheses, you are out of luck with regular expressions. This is impossible(*).

This regex just returns the text between the first opening and the last closing parentheses in your string.


(*) Unless your regex engine has features like balancing groups or recursion. The number of engines that support such features is slowly growing, but they are still not a commonly available.

Alan Moore
  • 73,866
  • 12
  • 100
  • 156
Tomalak
  • 332,285
  • 67
  • 532
  • 628
  • What do the "<=" and "=" signs mean? What regexp engine is this expression targeting? – Christian Klauser Feb 13 '09 at 15:58
  • 2
    This is look-around, or more correctly "zero width look-ahead/look-behind assertions". Most modern regex engines support them. – Tomalak Feb 13 '09 at 16:01
  • According to the OP's example, he wants to include the outermost parens in the match. This regex throws them away. – Alan Moore Feb 15 '09 at 05:09
  • 1
    @Alan M: You are right. But according to the question text, he wants everything _between_ the outermost parens. Pick your choice. He said he'd been trying for hours, so didn't even consider "everything including the outermost parens" as the intention, because it is so trivial: "\(.*\)". – Tomalak Feb 15 '09 at 10:29
  • Also, if you allow for recursive regular expressions, this is not "impossible." Adding "impossible" to StackOverflow questions without qualify when it is possible makes for bad reading. I would suggest adding a caveat for recursion, or discussing grammars. – hayesgm Jan 12 '15 at 07:47
  • 3
    @ghayes The answer is from 2009. That is a *long* time ago; regular expression engines that allow some form of recursion have been more uncommon than they are now (and they *still* are pretty uncommon). I'll mention it in my answer. – Tomalak Jan 12 '15 at 07:54
14

It is actually possible to do it using .NET regular expressions, but it is not trivial, so read carefully.

You can read a nice article here. You also may need to read up on .NET regular expressions. You can start reading here.

Angle brackets <> were used because they do not require escaping.

The regular expression looks like this:

<
[^<>]*
(
    (
        (?<Open><)
        [^<>]*
    )+
    (
        (?<Close-Open>>)
        [^<>]*
    )+
)*
(?(Open)(?!))
>
Alan Moore
  • 73,866
  • 12
  • 100
  • 156
Alexander Bartosh
  • 8,287
  • 1
  • 21
  • 22
12

I was also stuck in this situation when dealing with nested patterns and regular-expressions is the right tool to solve such problems.

/(\((?>[^()]+|(?1))*\))/
Stphane
  • 3,368
  • 5
  • 32
  • 47
Manish
  • 3,443
  • 1
  • 21
  • 24
  • 2
    As a user looking for help on a similar topic, I have no idea what that regex does specifically and how I can use it to apply it to my own problem. Perhaps this is a good answer but given the nature of regex being cryptic, I would have to look up every part of it just to see if this would help me. Given that there are so many answers with this type of "solution", I don't think I will. – Alex Mar 16 '22 at 00:25
  • 1
    https://regex101.com/ is a good explainer tool to exlpain this regex. – Mellester Jul 28 '22 at 13:24
  • This PCRE solution using ?1 works with (*SKIP)(*FAIL) when the ?R method posted by [bobble bubble](https://stackoverflow.com/a/35271017/1898524) does not. Use this solution if you need to find things that _ARE NOT_ in parenthesis. I created an example here: https://regex101.com/r/xkVzVP/1 – Ben Sep 29 '22 at 15:22
6

This is the definitive regex:

\(
(?<arguments> 
(  
  ([^\(\)']*) |  
  (\([^\(\)']*\)) |
  '(.*?)'

)*
)
\)

Example:

input: ( arg1, arg2, arg3, (arg4), '(pip' )

output: arg1, arg2, arg3, (arg4), '(pip'

note that the '(pip' is correctly managed as string. (tried in regulator: http://sourceforge.net/projects/regulator/)

Marco
  • 338
  • 2
  • 6
  • I like this technique if there's no nesting or you only care about the innermost group. It doesn't rely on recursion. I was able to use it to extract an argument that contained parenthesis. I made a working example at [Regex101](https://regex101.com/r/h5tpMO/2/) – Ben Oct 17 '20 at 03:24
5

The regular expression using Ruby (version 1.9.3 or above):

/(?<match>\((?:\g<match>|[^()]++)*\))/

Demo on rubular

nhahtdh
  • 55,989
  • 15
  • 126
  • 162
Joy Hu
  • 556
  • 5
  • 9
5

I have written a little JavaScript library called balanced to help with this task. You can accomplish this by doing

balanced.matches({
    source: source,
    open: '(',
    close: ')'
});

You can even do replacements:

balanced.replacements({
    source: source,
    open: '(',
    close: ')',
    replace: function (source, head, tail) {
        return head + source + tail;
    }
});

Here's a more complex and interactive example JSFiddle.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Chad Cache
  • 9,668
  • 3
  • 56
  • 48
5

Adding to bobble bubble's answer, there are other regex flavors where recursive constructs are supported.

Lua

Use %b() (%b{} / %b[] for curly braces / square brackets):

  • for s in string.gmatch("Extract (a(b)c) and ((d)f(g))", "%b()") do print(s) end (see demo)

Raku (former Perl6):

Non-overlapping multiple balanced parentheses matches:

my regex paren_any { '(' ~ ')' [ <-[()]>+ || <&paren_any> ]* }
say "Extract (a(b)c) and ((d)f(g))" ~~ m:g/<&paren_any>/;
# => (「(a(b)c)」 「((d)f(g))」)

Overlapping multiple balanced parentheses matches:

say "Extract (a(b)c) and ((d)f(g))" ~~ m:ov:g/<&paren_any>/;
# => (「(a(b)c)」 「(b)」 「((d)f(g))」 「(d)」 「(g)」)

See demo.

Python re non-regex solution

See poke's answer for How to get an expression between balanced parentheses.

Java customizable non-regex solution

Here is a customizable solution allowing single character literal delimiters in Java:

public static List<String> getBalancedSubstrings(String s, Character markStart, 
                                 Character markEnd, Boolean includeMarkers) 

{
        List<String> subTreeList = new ArrayList<String>();
        int level = 0;
        int lastOpenDelimiter = -1;
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            if (c == markStart) {
                level++;
                if (level == 1) {
                    lastOpenDelimiter = (includeMarkers ? i : i + 1);
                }
            }
            else if (c == markEnd) {
                if (level == 1) {
                    subTreeList.add(s.substring(lastOpenDelimiter, (includeMarkers ? i + 1 : i)));
                }
                if (level > 0) level--;
            }
        }
        return subTreeList;
    }
}

Sample usage:

String s = "some text(text here(possible text)text(possible text(more text)))end text";
List<String> balanced = getBalancedSubstrings(s, '(', ')', true);
System.out.println("Balanced substrings:\n" + balanced);
// => [(text here(possible text)text(possible text(more text)))]
Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
1

You need the first and last parentheses. Use something like this:

str.indexOf('('); - it will give you first occurrence

str.lastIndexOf(')'); - last one

So you need a string between,

String searchedString = str.substring(str1.indexOf('('),str1.lastIndexOf(')');
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Shell Scott
  • 1,679
  • 18
  • 28
1
"""
Here is a simple python program showing how to use regular
expressions to write a paren-matching recursive parser.

This parser recognises items enclosed by parens, brackets,
braces and <> symbols, but is adaptable to any set of
open/close patterns.  This is where the re package greatly
assists in parsing. 
"""

import re


# The pattern below recognises a sequence consisting of:
#    1. Any characters not in the set of open/close strings.
#    2. One of the open/close strings.
#    3. The remainder of the string.
# 
# There is no reason the opening pattern can't be the
# same as the closing pattern, so quoted strings can
# be included.  However quotes are not ignored inside
# quotes.  More logic is needed for that....


pat = re.compile("""
    ( .*? )
    ( \( | \) | \[ | \] | \{ | \} | \< | \> |
                           \' | \" | BEGIN | END | $ )
    ( .* )
    """, re.X)

# The keys to the dictionary below are the opening strings,
# and the values are the corresponding closing strings.
# For example "(" is an opening string and ")" is its
# closing string.

matching = { "(" : ")",
             "[" : "]",
             "{" : "}",
             "<" : ">",
             '"' : '"',
             "'" : "'",
             "BEGIN" : "END" }

# The procedure below matches string s and returns a
# recursive list matching the nesting of the open/close
# patterns in s.

def matchnested(s, term=""):
    lst = []
    while True:
        m = pat.match(s)

        if m.group(1) != "":
            lst.append(m.group(1))

        if m.group(2) == term:
            return lst, m.group(3)

        if m.group(2) in matching:
            item, s = matchnested(m.group(3), matching[m.group(2)])
            lst.append(m.group(2))
            lst.append(item)
            lst.append(matching[m.group(2)])
        else:
            raise ValueError("After <<%s %s>> expected %s not %s" %
                             (lst, s, term, m.group(2)))

# Unit test.

if __name__ == "__main__":
    for s in ("simple string",
              """ "double quote" """,
              """ 'single quote' """,
              "one'two'three'four'five'six'seven",
              "one(two(three(four)five)six)seven",
              "one(two(three)four)five(six(seven)eight)nine",
              "one(two)three[four]five{six}seven<eight>nine",
              "one(two[three{four<five>six}seven]eight)nine",
              "oneBEGINtwo(threeBEGINfourENDfive)sixENDseven",
              "ERROR testing ((( mismatched ))] parens"):
        print "\ninput", s
        try:
            lst, s = matchnested(s)
            print "output", lst
        except ValueError as e:
            print str(e)
    print "done"
Gene Olson
  • 890
  • 6
  • 4
1

The answer depends on whether you need to match matching sets of brackets, or merely the first open to the last close in the input text.

If you need to match matching nested brackets, then you need something more than regular expressions. - see @dehmann

If it's just first open to last close see @Zach

Decide what you want to happen with:

abc ( 123 ( foobar ) def ) xyz ) ghij

You need to decide what your code needs to match in this case.

Community
  • 1
  • 1
Douglas Leeder
  • 52,368
  • 9
  • 94
  • 137
0

This do not fully address the OP question but I though it may be useful to some coming here to search for nested structure regexp:

Parse parmeters from function string (with nested structures) in javascript

Match structures like:
Parse parmeters from function string

  • matches brackets, square brackets, parentheses, single and double quotes

Here you can see generated regexp in action

/**
 * get param content of function string.
 * only params string should be provided without parentheses
 * WORK even if some/all params are not set
 * @return [param1, param2, param3]
 */
exports.getParamsSAFE = (str, nbParams = 3) => {
    const nextParamReg = /^\s*((?:(?:['"([{](?:[^'"()[\]{}]*?|['"([{](?:[^'"()[\]{}]*?|['"([{][^'"()[\]{}]*?['")}\]])*?['")}\]])*?['")}\]])|[^,])*?)\s*(?:,|$)/;
    const params = [];
    while (str.length) { // this is to avoid a BIG performance issue in javascript regexp engine
        str = str.replace(nextParamReg, (full, p1) => {
            params.push(p1);
            return '';
        });
    }
    return params;
};
TOPKAT
  • 6,667
  • 2
  • 44
  • 72
0

because js regex doesn't support recursive match, i can't make balanced parentheses matching work.

so this is a simple javascript for loop version that make "method(arg)" string into array

push(number) map(test(a(a()))) bass(wow, abc)
$$(groups) filter({ type: 'ORGANIZATION', isDisabled: { $ne: true } }) pickBy(_id, type) map(test()) as(groups)
const parser = str => {
  let ops = []
  let method, arg
  let isMethod = true
  let open = []

  for (const char of str) {
    // skip whitespace
    if (char === ' ') continue

    // append method or arg string
    if (char !== '(' && char !== ')') {
      if (isMethod) {
        (method ? (method += char) : (method = char))
      } else {
        (arg ? (arg += char) : (arg = char))
      }
    }

    if (char === '(') {
      // nested parenthesis should be a part of arg
      if (!isMethod) arg += char
      isMethod = false
      open.push(char)
    } else if (char === ')') {
      open.pop()
      // check end of arg
      if (open.length < 1) {
        isMethod = true
        ops.push({ method, arg })
        method = arg = undefined
      } else {
        arg += char
      }
    }
  }

  return ops
}

// const test = parser(`$$(groups) filter({ type: 'ORGANIZATION', isDisabled: { $ne: true } }) pickBy(_id, type) map(test()) as(groups)`)
const test = parser(`push(number) map(test(a(a()))) bass(wow, abc)`)

console.log(test)

the result is like

[ { method: 'push', arg: 'number' },
  { method: 'map', arg: 'test(a(a()))' },
  { method: 'bass', arg: 'wow,abc' } ]
[ { method: '$$', arg: 'groups' },
  { method: 'filter',
    arg: '{type:\'ORGANIZATION\',isDisabled:{$ne:true}}' },
  { method: 'pickBy', arg: '_id,type' },
  { method: 'map', arg: 'test()' },
  { method: 'as', arg: 'groups' } ]
crapthings
  • 2,485
  • 3
  • 20
  • 33
0

While so many answers mention this in some form by saying that regex does not support recursive matching and so on, the primary reason for this lies in the roots of the Theory of Computation.

Language of the form {a^nb^n | n>=0} is not regular. Regex can only match things that form part of the regular set of languages.

Read more @ here

Prakhar Agrawal
  • 1,002
  • 12
  • 21
0

I didn't use regex since it is difficult to deal with nested code. So this snippet should be able to allow you to grab sections of code with balanced brackets:

def extract_code(data):
    """ returns an array of code snippets from a string (data)"""
    start_pos = None
    end_pos = None
    count_open = 0
    count_close = 0
    code_snippets = []
    for i,v in enumerate(data):
        if v =='{':
            count_open+=1
            if not start_pos:
                start_pos= i
        if v=='}':
            count_close +=1
            if count_open == count_close and not end_pos:
                end_pos = i+1
        if start_pos and end_pos:
            code_snippets.append((start_pos,end_pos))
            start_pos = None
            end_pos = None

    return code_snippets

I used this to extract code snippets from a text file.

Daniel
  • 2,028
  • 20
  • 18
-2

This might help to match balanced parenthesis.

\s*\w+[(][^+]*[)]\s*
Kishor Patil
  • 900
  • 7
  • 9
-4

This one also worked

re.findall(r'\(.+\)', s)
Hamid Mir
  • 363
  • 1
  • 9