Esta pregunta es muy pobre porque no está claro lo que está preguntando. Todas las respuestas lo interpretaron de manera diferente. @DaveF, ¿puedes aclarar la pregunta?
No estoy de acuerdo con que las expresiones regulares sean la herramienta incorrecta para esto por varias razones. 1) La mayoría de las implementaciones de expresiones regulares tienen una solución viable, si no perfecta, para esto. 2) A menudo está tratando de encontrar pares equilibrados de delimitadores en un contexto en el que también están en juego otros criterios adecuados para las expresiones regulares. 3) A menudo está entregando una expresión regular en alguna API que solo acepta expresiones regulares y no tiene otra opción.
Regex es la herramienta CORRECTA para el trabajo. Esta respuesta no es correcta. Ver la respuesta de rogal111.
Andrew
44
Absolutamente de acuerdo con la respuesta. Aunque hay algunas implementaciones de recursividad en regexp, son iguales a las máquinas de estado finito y no se supone que funcionen con estructuras anidadas, pero las Gramáticas sin contexto hacen esto. Mire la jerarquía de las gramáticas formales de Homsky.
Nick Roz el
138
Quiero agregar esta respuesta para referencia rápida. Siéntase libre de actualizar.
Cuando repites un grupo con un cuantificador posesivo, es inútil hacer que ese grupo sea atómico ya que todas las posiciones de retroceso en ese grupo se eliminan en cada repetición. Entonces escribir (?>[^)(]+|(?R))*+es lo mismo que escribir (?:[^)(]+|(?R))*+. Lo mismo para el próximo patrón. Acerca de la versión desenrollada, puede colocar un cuantificador posesivo aquí: [^)(]*+para evitar el retroceso (en caso de que no haya un corchete de cierre).
Casimir et Hippolyte
Sobre el patrón Ruby 1.9, en lugar de hacer que el grupo repetido sea atómico (que tiene un interés limitado cuando hay muchos paréntesis anidados (...(..)..(..)..(..)..(..)..)) en la cadena de asunto), puede usar un grupo simple que no captura y encerrar todo en un grupo atómico: (?>(?:[^)(]+|\g<1>)*)( esto se comporta exactamente como un cuantificador posesivo). En Ruby 2.x, el cuantificador posesivo está disponible.
Casimir et Hippolyte
@CasimiretHippolyte ¡Gracias! Ajusté los patrones PCRE y para Ruby 1.9, ¿te refieres a que todo el patrón sea así ? Por favor, siéntase libre de actualizarse. Entiendo lo que quieres decir, pero no estoy seguro de si hay muchas mejoras.
Un ejemplo sería realmente útil aquí, no puedo hacer que esto funcione para cosas como "(1, (2, 3)) (4, 5)".
Andy Hayden
44
@AndyHayden esto se debe a que "(1, (2, 3)) (4, 5)" tiene dos grupos separados con espacio. Use mi expresión regular con bandera global: / (([^ ()] | (? R)) *) / g. Aquí está la prueba en línea: regex101.com/r/lF0fI1/1
En .NET 4.5 me sale el siguiente error para este patrón: Unrecognized grouping construct.
nam
3
¡Increíble! Esta es una gran característica de regex. Gracias por ser el único que realmente responde la pregunta. Además, ese sitio regex101 es dulce.
Andrew
28
[^\(]*(\(.*\))[^\)]*
[^\(]*coincide con todo lo que no es un corchete de apertura al comienzo de la cadena, (\(.*\))captura la subcadena requerida entre corchetes y [^\)]*coincide con todo lo que no es un corchete de cierre al final de la cadena. Tenga en cuenta que esta expresión no intenta hacer coincidir los corchetes; un analizador simple (ver la respuesta de dehmann ) sería más adecuado para eso.
el corchete dentro de la clase no necesita ser escapado. Ya que por dentro no es un metacharacted.
José Leal
10
Este expr falla contra algo como "texto (texto) texto (texto) texto" retornando "(texto) texto (texto)". Las expresiones regulares no pueden contar corchetes.
Christian Klauser
17
(?<=\().*(?=\))
Si desea seleccionar texto entre dos paréntesis coincidentes , no tiene suerte con las expresiones regulares. Esto es imposible (*) .
Esta expresión regular solo devuelve el texto entre el primer paréntesis de apertura y el último de cierre en su cadena.
(*) A menos que su motor de expresiones regulares tenga características como grupos de equilibrio o recursividad . La cantidad de motores que admiten tales características está creciendo lentamente, pero todavía no están disponibles comúnmente.
¿Qué significan los signos "<=" y "="? ¿A qué motor de expresiones regulares se dirige esta expresión?
Christian Klauser
1
Esto es mirar alrededor, o más correctamente "aserciones de ancho cero para mirar hacia adelante / mirar hacia atrás". La mayoría de los motores regex modernos los admiten.
Tomalak
Según el ejemplo del OP, él quiere incluir a los padres más externos en el partido. Esta expresión regular los tira a la basura.
Alan Moore
1
@ Alan M: Tienes razón. Pero de acuerdo con el texto de la pregunta, él quiere todo entre los padres más externos. Elige tu elección. Dijo que había estado intentando durante horas, por lo que ni siquiera consideró "todo, incluidos los padres más externos" como la intención, porque es muy trivial: "(. *)".
Tomalak
3
@ghayes La respuesta es de 2009. Eso fue hace mucho tiempo; Los motores de expresión regular que permiten alguna forma de recursión han sido más infrecuentes de lo que son ahora (y aún son bastante infrecuentes). Lo mencionaré en mi respuesta.
Tomalak
14
Esta respuesta explica la limitación teórica de por qué las expresiones regulares no son la herramienta adecuada para esta tarea.
Las expresiones regulares no pueden hacer esto.
Las expresiones regulares se basan en un modelo informático conocido como Finite State Automata (FSA). Como su nombre lo indica, a FSApuede recordar solo el estado actual, no tiene información sobre los estados anteriores.
En el diagrama anterior, S1 y S2 son dos estados donde S1 es el paso inicial y final. Entonces, si intentamos con la cadena 0110, la transición es la siguiente:
0110-> S1 -> S2 -> S2 -> S2 ->S1
En los pasos anteriores, cuando estamos en el segundo S2es decir, después del análisis 01de 0110la FSA no tiene información acerca de la anterior 0en 01que sólo puede recordar el estado actual y el siguiente símbolo de entrada.
En el problema anterior, necesitamos saber el no de paréntesis de apertura; Esto significa que debe almacenarse en algún lugar. Pero como FSAsno puede hacer eso, no se puede escribir una expresión regular.
Sin embargo, se puede escribir un algoritmo para realizar esta tarea. Los algoritmos son generalmente cae bajo Pushdown Automata (PDA). PDAes un nivel por encima de FSA. PDA tiene una pila adicional para almacenar información adicional. Los PDA se pueden usar para resolver el problema anterior, porque podemos " push" el paréntesis de apertura en la pila y " pop" una vez que encontramos un paréntesis de cierre. Si al final, la pila está vacía, entonces se abren los paréntesis de apertura y cierre. De otra forma no.
Aquí hay varias respuestas, lo que demuestra que ES posible.
Jiří Herník
1
@Marco Esta respuesta habla sobre expresiones regulares en perspectiva teórica. ¡Muchos motores regex hoy en día no solo confían en este modelo teórico y usan memoria adicional para hacer el trabajo!
musibs
@ JiříHerník: esas no son expresiones regulares en sentido estricto: no están definidas como expresiones regulares por Kleene . Algunos motores de expresión regular han implementado algunas capacidades adicionales, haciéndolos analizar más que solo lenguajes regulares .
Willem Van Onsem
12
En realidad, es posible hacerlo utilizando expresiones regulares .NET, pero no es trivial, así que léalo detenidamente.
Puedes leer un buen artículo aquí . También es posible que necesite leer en expresiones regulares .NET. Puedes empezar a leer aquí .
<>Se usaron corchetes angulares porque no requieren escapar.
"""
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 =[]whileTrue:
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:raiseValueError("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
exceptValueErroras e:print str(e)print"done"
La respuesta depende de si necesita hacer coincidir los conjuntos de paréntesis coincidentes, o simplemente la primera apertura hasta el último cierre en el texto de entrada.
Si necesita hacer coincidir los corchetes anidados, entonces necesita algo más que expresiones regulares. - ver @dehmann
Si solo se abre por primera vez y se cierra, vea @Zach
Decide con qué quieres que suceda:
abc (123( foobar )def) xyz ) ghij
Debe decidir qué debe coincidir con su código en este caso.
Si bien muchas respuestas mencionan esto de alguna forma al decir que regex no admite la coincidencia recursiva, etc., la razón principal de esto radica en las raíces de la Teoría de la Computación.
Idioma de la forma {a^nb^n | n>=0} is not regular. Regex solo puede coincidir con elementos que forman parte del conjunto regular de idiomas.
No utilicé regex ya que es difícil lidiar con código anidado. Por lo tanto, este fragmento debería permitirle tomar secciones de código con corchetes equilibrados:
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+=1ifnot start_pos:
start_pos= i
if v=='}':
count_close +=1if count_open == count_close andnot end_pos:
end_pos = i+1if start_pos and end_pos:
code_snippets.append((start_pos,end_pos))
start_pos =None
end_pos =Nonereturn code_snippets
Utilicé esto para extraer fragmentos de código de un archivo de texto.
/**
* 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*(?:,|$)/;constparams=[];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'';});}returnparams;};
Esto no aborda completamente la pregunta de OP, pero creo que puede ser útil para algunos que vienen aquí a buscar expresiones regulares de estructura anidadas.
Respuestas:
Las expresiones regulares son la herramienta incorrecta para el trabajo porque se trata de estructuras anidadas, es decir, recursividad.
Pero hay un algoritmo simple para hacer esto, que describí en esta respuesta a una pregunta anterior .
fuente
Quiero agregar esta respuesta para referencia rápida. Siéntase libre de actualizar.
.NET Regex utilizando grupos de equilibrio .
Donde
c
se usa como el contador de profundidad.Demo en Regexstorm.com
PCRE utilizando un patrón recursivo .
Demo en regex101 ; O sin alternancia:
Demo en regex101 ; O desenrollado para el rendimiento:
Demo en regex101 ; El patrón se pega en el
(?R)
que representa(?0)
.Perl, PHP, Notepad ++, R : perl = TRUE , paquete Python : Regex con
(?V1)
comportamiento Perl.Ruby usando llamadas subexpresoras .
Con Ruby 2.0
\g<0>
se puede usar para llamar al patrón completo.Demo en Rubular ; Ruby 1.9 solo admite la captura de recursividad grupal :
Demostración en Rubular ( agrupación atómica desde Ruby 1.9.3)
API de JavaScript :: XRegExp.matchRecursive
JS, Java y otros sabores de expresiones regulares sin recurrencia hasta 2 niveles de anidamiento:
Demo en regex101 . Se necesita agregar una anidación más profunda al patrón.
Para fallar más rápido en paréntesis desequilibrados, suelte el
+
cuantificador.Java : una idea interesante utilizando referencias avanzadas de @jaytea .
Referencia: ¿qué significa esta expresión regular?
fuente
(?>[^)(]+|(?R))*+
es lo mismo que escribir(?:[^)(]+|(?R))*+
. Lo mismo para el próximo patrón. Acerca de la versión desenrollada, puede colocar un cuantificador posesivo aquí:[^)(]*+
para evitar el retroceso (en caso de que no haya un corchete de cierre).(...(..)..(..)..(..)..(..)..)
) en la cadena de asunto), puede usar un grupo simple que no captura y encerrar todo en un grupo atómico:(?>(?:[^)(]+|\g<1>)*)
( esto se comporta exactamente como un cuantificador posesivo). En Ruby 2.x, el cuantificador posesivo está disponible.Puede usar la recursividad regex :
fuente
Unrecognized grouping construct
.[^\(]*
coincide con todo lo que no es un corchete de apertura al comienzo de la cadena,(\(.*\))
captura la subcadena requerida entre corchetes y[^\)]*
coincide con todo lo que no es un corchete de cierre al final de la cadena. Tenga en cuenta que esta expresión no intenta hacer coincidir los corchetes; un analizador simple (ver la respuesta de dehmann ) sería más adecuado para eso.fuente
Si desea seleccionar texto entre dos paréntesis coincidentes , no tiene suerte con las expresiones regulares. Esto es imposible (*) .
Esta expresión regular solo devuelve el texto entre el primer paréntesis de apertura y el último de cierre en su cadena.
(*) A menos que su motor de expresiones regulares tenga características como grupos de equilibrio o recursividad . La cantidad de motores que admiten tales características está creciendo lentamente, pero todavía no están disponibles comúnmente.
fuente
Esta respuesta explica la limitación teórica de por qué las expresiones regulares no son la herramienta adecuada para esta tarea.
Las expresiones regulares no pueden hacer esto.
Las expresiones regulares se basan en un modelo informático conocido como
Finite State Automata (FSA)
. Como su nombre lo indica, aFSA
puede recordar solo el estado actual, no tiene información sobre los estados anteriores.En el diagrama anterior, S1 y S2 son dos estados donde S1 es el paso inicial y final. Entonces, si intentamos con la cadena
0110
, la transición es la siguiente:En los pasos anteriores, cuando estamos en el segundo
S2
es decir, después del análisis01
de0110
la FSA no tiene información acerca de la anterior0
en01
que sólo puede recordar el estado actual y el siguiente símbolo de entrada.En el problema anterior, necesitamos saber el no de paréntesis de apertura; Esto significa que debe almacenarse en algún lugar. Pero como
FSAs
no puede hacer eso, no se puede escribir una expresión regular.Sin embargo, se puede escribir un algoritmo para realizar esta tarea. Los algoritmos son generalmente cae bajo
Pushdown Automata (PDA)
.PDA
es un nivel por encima deFSA
. PDA tiene una pila adicional para almacenar información adicional. Los PDA se pueden usar para resolver el problema anterior, porque podemos "push
" el paréntesis de apertura en la pila y "pop
" una vez que encontramos un paréntesis de cierre. Si al final, la pila está vacía, entonces se abren los paréntesis de apertura y cierre. De otra forma no.fuente
En realidad, es posible hacerlo utilizando expresiones regulares .NET, pero no es trivial, así que léalo detenidamente.
Puedes leer un buen artículo aquí . También es posible que necesite leer en expresiones regulares .NET. Puedes empezar a leer aquí .
<>
Se usaron corchetes angulares porque no requieren escapar.La expresión regular se ve así:
fuente
Esta es la expresión regular definitiva:
Ejemplo:
tenga en cuenta que
'(pip'
se gestiona correctamente como una cadena. (probado en el regulador: http://sourceforge.net/projects/regulator/ )fuente
He escrito una pequeña biblioteca de JavaScript llamada balanceada para ayudar con esta tarea. Puedes lograr esto haciendo
Incluso puedes hacer reemplazos:
Aquí hay un ejemplo más complejo e interactivo de JSFiddle .
fuente
Además de la respuesta de bobble bubble , hay otros sabores regex donde se admiten construcciones recursivas.
Lua
Uso
%b()
(%b{}
/%b[]
para llaves / corchetes):for s in string.gmatch("Extract (a(b)c) and ((d)f(g))", "%b()") do print(s) end
(ver demo )Perl6 :
Coincide con paréntesis equilibrados múltiples no superpuestos:
Superposición de coincidencias de paréntesis equilibrados múltiples:
Ver demo .
re
Solución Python no regexVea la respuesta de poke para Cómo obtener una expresión entre paréntesis equilibrados .
Solución Java no regex personalizable
Aquí hay una solución personalizable que permite delimitadores literales de un solo carácter en Java:
Uso de la muestra:
fuente
La expresión regular que usa Ruby (versión 1.9.3 o superior):
Demo en rubular
fuente
Necesitas el primer y último paréntesis. Usa algo como esto:
str.indexOf ('('); - te dará la primera aparición
str.lastIndexOf (')'); - el último
Entonces necesitas una cuerda entre,
fuente
fuente
La respuesta depende de si necesita hacer coincidir los conjuntos de paréntesis coincidentes, o simplemente la primera apertura hasta el último cierre en el texto de entrada.
Si necesita hacer coincidir los corchetes anidados, entonces necesita algo más que expresiones regulares. - ver @dehmann
Si solo se abre por primera vez y se cierra, vea @Zach
Decide con qué quieres que suceda:
Debe decidir qué debe coincidir con su código en este caso.
fuente
porque js regex no admite la coincidencia recursiva, no puedo hacer que la combinación de paréntesis equilibrados funcione.
así que este es un javascript simple para la versión de bucle que convierte la cadena "método (arg)" en una matriz
el resultado es como
fuente
Si bien muchas respuestas mencionan esto de alguna forma al decir que regex no admite la coincidencia recursiva, etc., la razón principal de esto radica en las raíces de la Teoría de la Computación.
Idioma de la forma
{a^nb^n | n>=0} is not regular
. Regex solo puede coincidir con elementos que forman parte del conjunto regular de idiomas.Leer más @ aquí
fuente
No utilicé regex ya que es difícil lidiar con código anidado. Por lo tanto, este fragmento debería permitirle tomar secciones de código con corchetes equilibrados:
Utilicé esto para extraer fragmentos de código de un archivo de texto.
fuente
También me quedé atrapado en esta situación donde vienen los patrones anidados.
La expresión regular es lo correcto para resolver el problema anterior. Usar debajo del patrón
fuente
Este también funcionó
fuente
Esto puede ser útil para algunos:
Analiza los parámetros de la cadena de función (con estructuras anidadas) en javascript
Combina estructuras como:
Aquí puedes ver expresiones regulares generadas en acción
Esto no aborda completamente la pregunta de OP, pero creo que puede ser útil para algunos que vienen aquí a buscar expresiones regulares de estructura anidadas.
fuente