Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Regex nested parentheses

I have the following string:

a,b,c,d.e(f,g,h,i(j,k)),l,m,n

Would know tell me how I could build a regex that returns me only the "first level" of parentheses something like this:

[0] = a,b,c,
[1] = d.e(f,g,h,i.j(k,l))
[2] = m,n

The goal would be to keep the section that has the same index in parentheses nested to manipulate future.

Thank you.

EDIT

Trying to improve the example...

Imagine I have this string

username,TB_PEOPLE.fields(FirstName,LastName,TB_PHONE.fields(num_phone1, num_phone2)),password

My goal is to turn a string into a dynamic query. Then the fields that do not begin with "TB_" I know they are fields of the main table, otherwise I know informandos fields within parentheses, are related to another table. But I am having difficulty retrieving all fields "first level" since I can separate them from related tables, I could go recursively recovering the remaining fields.

In the end, would have something like:

[0] = username,password
[1] = TB_PEOPLE.fields(FirstName,LastName,TB_PHONE.fields(num_phone1, num_phone2))

I hope I have explained a little better, sorry.

like image 365
Verner Avatar asked Oct 25 '13 17:10

Verner


People also ask

Can you use parentheses in regex?

By placing part of a regular expression inside round brackets or parentheses, you can group that part of the regular expression together. This allows you to apply a quantifier to the entire group or to restrict alternation to part of the regex. Only parentheses can be used for grouping.

What is difference [] and () in regex?

In other words, square brackets match exactly one character. (a-z0-9) will match two characters, the first is one of abcdefghijklmnopqrstuvwxyz , the second is one of 0123456789 , just as if the parenthesis weren't there. The () will allow you to read exactly which characters were matched.

What do the [] brackets mean in regular expressions?

Square brackets ( “[ ]” ): Any expression within square brackets [ ] is a character set; if any one of the characters matches the search string, the regex will pass the test return true.


1 Answers

You can use this:

(?>\w+\.)?\w+\((?>\((?<DEPTH>)|\)(?<-DEPTH>)|[^()]+)*\)(?(DEPTH)(?!))|\w+

With your example you obtain:

0 => username
1 => TB_PEOPLE.fields(FirstName,LastName,TB_PHONE.fields(num_phone1, num_phone2))
2 => password

Explanation:

(?>\w+\.)? \w+ \(    # the opening parenthesis (with the function name)
(?>                  # open an atomic group
    \(  (?<DEPTH>)   # when an opening parenthesis is encountered,
                     #  then increment the stack named DEPTH
  |                  # OR
    \) (?<-DEPTH>)   # when a closing parenthesis is encountered,
                     #  then decrement the stack named DEPTH
  |                  # OR
    [^()]+           # content that is not parenthesis
)*                   # close the atomic group, repeat zero or more times
\)                   # the closing parenthesis
(?(DEPTH)(?!))       # conditional: if the stack named DEPTH is not empty
                     #  then fail (ie: parenthesis are not balanced)

You can try it with this code:

string input = "username,TB_PEOPLE.fields(FirstName,LastName,TB_PHONE.fields(num_phone1, num_phone2)),password";
string pattern = @"(?>\w+\.)?\w+\((?>\((?<DEPTH>)|\)(?<-DEPTH>)|[^()]+)*\)(?(DEPTH)(?!))|\w+";
MatchCollection matches = Regex.Matches(input, pattern);
foreach (Match match in matches)
{
    Console.WriteLine(match.Groups[0].Value);
}
like image 71
Casimir et Hippolyte Avatar answered Sep 21 '22 10:09

Casimir et Hippolyte