Regex paréntesis nesteds

Tengo la siguiente cadena:

a,b,c,de(f,g,h,i(j,k)),l,m,n 

Sabría decirme cómo podría crear una expresión regular que me devuelva solo el “primer nivel” de paréntesis, algo como esto:

 [0] = a,b,c, [1] = de(f,g,h,ij(k,l)) [2] = m,n 

El objective sería mantener anidada la sección que tiene el mismo índice entre paréntesis para manipular el futuro.

Gracias.

EDITAR

Tratando de mejorar el ejemplo …

Imagina que tengo esta cadena

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

Mi objective es convertir una cadena en una consulta dinámica. Entonces los campos que no comienzan con “TB_” sé que son campos de la tabla principal, de lo contrario sé que los campos de información entre paréntesis están relacionados con otra tabla. Pero estoy teniendo dificultades para recuperar todos los campos de “primer nivel” ya que puedo separarlos de las tablas relacionadas, podría ir recursivamente recuperando los campos restantes.

Al final, tendría algo como:

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

Espero haber explicado un poco mejor, lo siento.

Puedes usar esto:

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

Con tu ejemplo, obtienes:

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

Explicación:

 (?>\w+\.)? \w+ \( # the opening parenthesis (with the function name) (?> # open an atomic group \( (?) # 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) 

Puedes probarlo con este código:

 string input = "username,TB_PEOPLE.fields(FirstName,LastName,TB_PHONE.fields(num_phone1, num_phone2)),password"; string pattern = @"(?>\w+\.)?\w+\((?>\((?)|\)(?<-DEPTH>)|[^()]+)*\)(?(DEPTH)(?!))|\w+"; MatchCollection matches = Regex.Matches(input, pattern); foreach (Match match in matches) { Console.WriteLine(match.Groups[0].Value); } 

Sugiero una nueva estrategia, R2: hágalo algorítmicamente. Si bien puedes construir un Regex que eventualmente se acerque a lo que estás preguntando, será enormemente imposible de mantener, y difícil de ampliar cuando encuentres nuevos casos extremos. No hablo C #, pero este pseudo código debería llevarlo por el camino correcto:

 function parenthetical_depth(some_string): open = count '(' in some_string close = count ')' in some_string return open - close function smart_split(some_string): bits = split some_string on ',' new_bits = empty list bit = empty string while bits has next: bit = fetch next from bits while parenthetical_depth(bit) != 0: bit = bit + ',' + fetch next from bits place bit into new_bits return new_bits 

Esta es la forma más fácil de entenderlo, el algoritmo es actualmente O(n^2) – hay una optimización para que el bucle interno lo haga O(n) (con la excepción de la copia de cadenas, que es una especie de la peor parte de esta):

 depth = parenthetical_depth(bit) while depth != 0: nbit = fetch next from bits depth = depth + parenthetical_depth(nbit) bit = bit + ',' + nbit 

La copia de cadenas se puede hacer más eficiente con el uso inteligente de almacenamientos intermedios y el tamaño del búfer, a costa de la eficiencia del espacio, pero no creo que C # le brinde ese nivel de control de forma nativa.

Si entendí correctamente tu ejemplo, estás buscando algo como esto:

 (?[a-zA-Z._]+\,)*(?[a-zA-Z._]+[(].*[)])(?.*) 

Para cadena dada:

nombre de usuario, TB_PEOPLE.fields (FirstName, LastName, TB_PHONE.fields (num_phone1, num_phone2)), contraseña

Esta expresión coincidirá

  • nombre de usuario, para cabeza de grupo
  • TB_PEOPLE.fields (FirstName, LastName, TB_PHONE.fields (num_phone1, num_phone2)) para el cuerpo del grupo
  • , contraseña para cola de grupo