regex - online - Expresión regular para que coincida con los soportes externos
regex python (15)
Éste también funcionó
re.findall(r''/(.+/)'', s)
Necesito una expresión regular para seleccionar todo el texto entre dos corchetes externos.
Ejemplo: some text(text here(possible text)text(possible text(more text)))end text
Resultado: (text here(possible text)text(possible text(more text)))
Lo he intentado durante horas, pero mi conocimiento de expresiones regulares no es lo que me gustaría que fuera :-) por lo que cualquier ayuda será recibida con gratitud.
Aquí hay una solución personalizable que permite delimitadores literales de un solo carácter en 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;
}
}
Uso de la muestra:
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)))]
En realidad, es posible hacerlo utilizando expresiones regulares .NET, pero no es trivial, así que lea detenidamente.
Puedes leer un buen artículo here . También es posible que deba leer sobre expresiones regulares .NET. Puedes empezar a leer here .
Los corchetes angulares <>
se utilizaron porque no requieren escape.
La expresión regular se ve así:
<
[^<>]*
(
(
(?<Open><)
[^<>]*
)+
(
(?<Close-Open>>)
[^<>]*
)+
)*
(?(Open)(?!))
>
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, una FSA
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:
0 1 1 0
-> S1 -> S2 -> S2 -> S2 ->S1
En los pasos anteriores, cuando estamos en el segundo S2
es decir, después de analizar 01
de 0110
, la FSA no tiene información sobre el 0
en 01
ya que solo 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 tiene que ser almacenado en algún lugar. Pero como las FSAs
no pueden hacer eso, no se puede escribir una expresión regular.
Sin embargo, se puede escribir un algoritmo para lograr el objetivo. Los algoritmos generalmente están Pushdown Automata (PDA)
. PDA
es un nivel por encima de FSA
. PDA tiene una pila adicional para almacenar algo. Las 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 nos encontramos con un paréntesis de cierre. Si al final, la pila está vacía, entonces abriendo paréntesis y cerrando paréntesis coincide. De otra forma no.
Una discusión detallada se puede encontrar here .
Este es el regex definitivo:
/(
(?<arguments>
(
([^/(/)'']*) |
(/([^/(/)'']*/)) |
''(.*?)''
)*
)
/)
Ejemplo:
input: ( arg1, arg2, arg3, (arg4), ''(pip'' )
output: arg1, arg2, arg3, (arg4), ''(pip''
tenga en cuenta que el ''(pip''
se administra correctamente como una cadena. (probado en el regulador: http://sourceforge.net/projects/regulator/ )
He escrito una pequeña biblioteca de javascript llamada balanced para ayudar con esta tarea, puede lograr esto haciendo
balanced.matches({
source: source,
open: ''('',
close: '')''
});
incluso puedes hacer reemplazos
balanced.replacements({
source: source,
open: ''('',
close: '')'',
replace: function (source, head, tail) {
return head + source + tail;
}
});
Heres un ejemplo más complejo e interactivo JSFiddle
La expresión regular usando Ruby (versión 1.9.3 o superior):
/(?<match>/((?:/g<match>|[^()]++)*/))/
La respuesta depende de si necesita hacer coincidir conjuntos de corchetes o simplemente la primera apertura hasta el último cierre en el texto de entrada.
Si necesita hacer coincidir corchetes anidados coincidentes, entonces necesita algo más que expresiones regulares. - ver @dehmann
Si es la primera vez que se abre por última vez, vea @Zach
Decide qué quieres que pase con:
abc ( 123 ( foobar ) def ) xyz ) ghij
Debe decidir qué debe coincidir con su código en este caso.
Las expresiones regulares son la herramienta incorrecta para el trabajo porque se trata de estructuras anidadas, es decir, recursión.
Pero hay un algoritmo simple para hacer esto, que describí en esta respuesta a una pregunta anterior .
Puedes usar la expresión regular de expresiones regulares :
/(([^()]|(?R))*/)
Quiero añadir esta respuesta para referencia rápida. Siéntase libre de actualizar.
.NET Regex utilizando grupos de balanceo .
/((?>/((?<c>)|[^()]+|/)(?<-c>))*(?(c)(?!))/)
Donde c
se utiliza como contador de profundidad.
- Desbordamiento de pila : uso de RegEx para equilibrar paréntesis de coincidencia
- El desconcertante blog de Wes : emparejando construcciones equilibradas con expresiones regulares de .NET
- El blog de Greg Reinacker : construcciones anidadas en expresiones regulares
PCRE utilizando un patrón recursivo .
/((?>[^)(]+|(?R))*+/)
Demo en regex101 ; O sin alternancia:
/((?>[^)(]*(?R)?)*+/)
Demo en regex101 ; O unrolled para el rendimiento:
/([^)(]*(?:(?R)[^)(]*)*+/)
Demo en regex101 ; El patrón se pega en (?R)
que representa (?0)
.
Perl, PHP, Notepad ++, R : perl=TRUE , Python : paquete Regex con (?V1)
para el comportamiento de Perl.
Ruby utilizando subexpresiones .
Con Ruby 2.0 /g<0>
se puede usar para llamar patrón completo.
/((?>[^)(]+|/g<0>)*/)
Demo en Rubular ; Ruby 1.9 solo admite la recursión grupal de captura :
(/((?>[^)(]+|/g<1>)*/))
Demostración en Rubular ( agrupación atómica desde Ruby 1.9.3)
API de JavaScript :: XRegExp.matchRecursive
XRegExp.matchRecursive(str, ''//('', ''//)'', ''g'');
JS, Java y otros sabores de expresiones regulares sin recursión hasta 2 niveles de anidamiento:
/((?:[^)(]+|/((?:[^)(]+|/([^)(]*/))*/))*/)
Demostración en regex101 . Es necesario agregar un anidamiento más profundo al patrón.
Para fallar más rápido en paréntesis desequilibrados, suelte el cuantificador +
.
Java : una idea interesante usando referencias hacia adelante por @jaytea .
Referencia - ¿Qué significa esta expresión regular?
así que necesitas primero y último paréntesis, usa algo así como str.indexOf (''(''); - te dará la primera aparición str.lastIndexOf ('')''); - el último
así que u necesitas una cadena entre, String searchString = str.substring (str1.indexOf (''(''), str1.lastIndexOf ('')'');
"""
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"
(?<=/().*(?=/))
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 la primera apertura y los últimos paréntesis de cierre en su cadena.
(*) A menos que su motor de expresiones regulares tenga características como equilibrar grupos o recursividad . La cantidad de motores que admiten estas características está creciendo lentamente, pero aún no están disponibles comúnmente.
[^/(]*(/(.*/))[^/)]*
[^/(]*
coincide con todo lo que no es un corchete de apertura al principio de la cadena, (/(.*/))
captura la subcadena requerida entre corchetes, y [^/)]*
coincide con todo lo que no es '' t un corchete de cierre al final de la cadena. Tenga en cuenta que esta expresión no intenta hacer coincidir corchetes; un analizador simple (ver la respuesta de dehmann ) sería más adecuado para eso.