Estaba leyendo una pregunta acerca de cómo obtener datos de interior doble llaves ( esta pregunta ) y, a continuación, alguien que creció el equilibrio de los grupos. Todavía no estoy muy seguro de qué son y cómo usarlos.

He leído a través de Equilibrio De La Definición De Grupo, pero la explicación es difícil de seguir, y todavía estoy un poco confundida sobre las cuestiones que he mencionado.

Podría alguien explicar simplemente lo que el equilibrio de los grupos y cómo son útiles?

  • Me pregunto en cuántos regex engiens este es en realidad el apoyo.
  • Se apoya en, al menos, el .NET Regex motor.

2 Comentarios

  1. 166

    Hasta donde yo sé, el equilibrio de los grupos son únicos .NET regex sabor.

    De Lado: Los Grupos Repetidos

    Primer lugar, usted necesita saber que .NET es (de nuevo, que yo sepa) la única regex sabor que le permite acceder a múltiples capturas de un solo grupo de captura (no en el retro-referencias pero después de que el partido se haya completado).

    Para ilustrar esto con un ejemplo, considere el patrón de

    (.)+

    y la cadena de "abcd".

    en todos los demás regex sabores, grupo de captura 1 simplemente producir un resultado: d (nota, el partido completo, por supuesto, ser abcd como se esperaba). Esto es debido a que en cada nuevo uso de la captura de grupo sobrescribe la anterior captura.

    .NETO por otro lado, recuerda a todos ellos. Y lo hace en una pila. Después de la coincidencia de las anteriores regex como

    Match m = new Regex(@"(.)+").Match("abcd");

    usted encontrará que

    m.Groups[1].Captures

    Es un CaptureCollection cuyos elementos corresponden a las cuatro capturas

    0: "a"
    1: "b"
    2: "c"
    3: "d"

    donde el número es el índice en el CaptureCollection. Así que, básicamente, cada vez que el grupo se utiliza de nuevo, una nueva captura se inserta en la pila.

    Se pone más interesante si estamos utilizando denominado grupos de captura. Porque .NET permite el uso repetido del mismo nombre, podemos escribir una expresión regular como

    (?<word>\w+)\W+(?<word>\w+)

    a la captura de dos palabras en el mismo grupo. De nuevo, cada vez que un grupo con un cierto nombre se encuentra, la captura es empujada a la pila. De manera que al aplicar esta expresión a la entrada "foo bar" y la inspección de

    m.Groups["word"].Captures

    nos encontramos con dos capturas

    0: "foo"
    1: "bar"

    Esto nos permite incluso llevar las cosas en una sola pila de diferentes partes de la expresión. Pero aún así, esto es sólo .NETO de la característica de poder realizar el seguimiento de varios captura que se enumeran en este CaptureCollection. Pero me dije, esta es una colección de pila. Así, podemos pop cosas de ella?

    Entrar: El Equilibrio De Los Grupos De

    Resulta que podemos. Si utilizamos un grupo como (?<-word>...), luego de la última captura se apareció de la pila word si la subexpresión ... partidos. Así que si cambiamos nuestra expresión anterior para

    (?<word>\w+)\W+(?<-word>\w+)

    A continuación, un segundo grupo de pop el primer grupo de captura, y vamos a recibir un vacío CaptureCollection en la final. Por supuesto, este ejemplo es bastante inútil.

    Pero hay un detalle más a las menos-sintaxis: si la pila está vacía, el grupo no puede (independientemente de su patrón). Podemos aprovechar este comportamiento para el recuento de los niveles de anidamiento, y aquí es donde el nombre de equilibrio de grupo viene (y donde se pone interesante). Digamos que queremos para que coincida con las cadenas que están correctamente entre paréntesis. Empujamos cada uno de los paréntesis de apertura en la pila, y aparecerá una captura para cada uno de los paréntesis de cierre. Si nos encontramos con un paréntesis de cierre demasiados, intentará pop una pila vacía y causar el patrón de falla:

    ^(?:[^()]|(?<Open>[(])|(?<-Open>[)]))*$

    Así que tenemos tres alternativas en una repetición. La primera alternativa consume todo lo que no es un paréntesis. La segunda alternativa coincide con (s mientras empuja a la pila. La tercera alternativa que coincide con )s mientras apareciendo elementos de la pila (si es posible!).

    Nota: Solo para aclarar, estamos a sólo comprobar que no hay ningún paréntesis sueltos! Esto significa que la cadena no contiene paréntesis en todos los se partido, debido a que aún están sintácticamente válida (en algunos sintaxis de donde usted necesita su paréntesis para que coincida). Si desea asegurarse de que al menos un conjunto de paréntesis, basta con añadir un lookahead (?=.*[(]) a la derecha después de la ^.

    Este patrón no es perfecta (o del todo correcto), aunque.

    Final: Condicional Patrones

    Hay uno más capturas: esto no garantiza que la pila está vacía al final de la cadena (de ahí (foo(bar) sería válido). .NET (y muchos otros sabores) tiene una construcción que nos ayuda aquí: condicional patrones. La sintaxis general es la

    (?(condition)truePattern|falsePattern)

    donde el falsePattern es opcional, si se omite el falso caso siempre coinciden. La condición puede ser un patrón, o el nombre de un grupo de captura. Me centraré en este último caso aquí. Si es el nombre de un grupo de captura, luego truePattern se utiliza si y sólo si la captura de la pila para ese grupo en particular no está vacío. Es decir, un condicional patrón de (?(name)yes|no) lee «si name ha encontrado y capturado algo (que todavía está en la pila), patrón de uso yes de lo contrario, el patrón de uso.no«.

    Así que al final de nuestro modelo anterior podríamos añadir algo como (?(Open)failPattern) que hace que el patrón completo a fallar, si el Opende la pila no está vacía. La cosa más simple de hacer que el patrón incondicionalmente no es (?!) (un vacío negativo lookahead). Así que tenemos nuestro patrón final:

    ^(?:[^()]|(?<Open>[(])|(?<-Open>[)]))*(?(Open)(?!))$

    Tenga en cuenta que este condicional de la sintaxis no tiene nada per se que hacer con el equilibrio de los grupos, pero es necesario para aprovechar su pleno poder.

    A partir de aquí, el cielo es el límite. Muchos muy sofisticado usos son posibles y existen algunas trampas cuando se utiliza en combinación con otros .NET-Regex características como longitud variable lookbehinds (que tuve que aprender de la manera difícil a mí mismo). La cuestión principal, sin embargo, es la de siempre: es el código todavía fácil de mantener cuando el uso de estas características? Usted tiene que documentar muy bien, y asegúrese de que todos los que trabajan en ella también es consciente de estas características. De lo contrario, usted puede ser mejor, simplemente caminar en la cuerda manualmente los caracteres, y contando los niveles de anidamiento en un entero.

    Addendum: ¿Qué pasa con el (?<A-B>...) sintaxis?

    Créditos para esta parte ir a Kobi (véase su respuesta a continuación para más detalles).

    Ahora con todo lo anterior, podemos validar que una cadena está correctamente entre paréntesis. Pero sería mucho más útil, si se podría conseguir (anidada) captura para todos los paréntesis contenidos. Por supuesto, podríamos recordar la apertura y el cierre de paréntesis en una separada de captura de pila no está vacía, y luego hacer algo de extracción de subcadena según sus posiciones en un paso separado.

    Pero .NET proporciona una mayor comodidad característica de aquí: si usamos (?<A-B>subPattern), no sólo es una captura de estallar de la pila B, sino también todo lo que entre que apareció la captura de B y este grupo se inserta en la pila de A. Por lo que si utilizamos un grupo como este para el paréntesis de cierre, mientras que el de hacer estallar los niveles de anidamiento de nuestra pila, también podemos empujar a la par del contenido en otra pila:

    ^(?:[^()]|(?<Open>[(])|(?<Content-Open>[)]))*(?(Open)(?!))$

    Kobi siempre esta En Vivo-Demo en su respuesta

    Por lo que tomar todas estas cosas juntos podemos:

    • Recordar arbitrariamente muchos captura
    • Validar las estructuras anidadas
    • De captura de cada nivel de anidamiento

    Todo en una sola expresión regular. Si eso no es emocionante… 😉

    Algunos recursos que he encontrado útil cuando aprendí acerca de ellos:

  2. 38

    Sólo una pequeña adición a M. Buettner excelente respuesta:

    ¿Cuál es el trato con el (?<A-B>) sintaxis?

    (?<A-B>x) es sutilmente diferente de (?<-A>(?<B>x)). El resultado es que el mismo flujo de control*, pero captura de manera diferente.

    Por ejemplo, echemos un vistazo a un patrón para equilibrado de llaves:

    (?:[^{}]|(?<B>{)|(?<-B>}))+(?(B)(?!))

    Al final del partido, tenemos un equilibrado de la cadena, pero eso es todo lo que tenemos, no sabemos donde las llaves son, porque la B pila está vacía. El trabajo duro, el motor hizo por nosotros se ha ido.

    (ejemplo en Regex Tormenta)

    (?<A-B>x) es la solución para ese problema. Cómo? Es no captura x en $A: captura el contenido entre la anterior captura de B y la posición actual.

    Lo vamos a usar en nuestro modelo:

    (?:[^{}]|(?<Open>{)|(?<Content-Open>}))+(?(Open)(?!))

    Esta sería la captura en $Content las cuerdas entre las llaves (y sus posiciones), para cada par a lo largo del camino.

    Para la cadena {1 2 {3} {4 5 {6}} 7} había cuatro capturas: 3, 6 ,4 5 {6} , y 1 2 {3} {4 5 {6}} 7 – mucho mejor que nada o } } } }.

    (ejemplo – haga clic en el tabla ficha y la mirada en ${Contenido}, captura)

    De hecho, puede ser utilizado sin el equilibrio en todo: (?<a>).(.(?<Contenido-A>).) captura de los dos primeros personajes, aunque estén separados por grupos.

    (un lookahead es más comúnmente utilizado aquí, pero no siempre de escala: se pueden duplicar su lógica.)

    (?<A-B>) es una característica fuerte - le da exacta control sobre su captura. Mantenga esto en mente cuando usted está tratando de obtener más de su patrón.

    • continuando con la discusión de la la pregunta que no le gusta en una nueva respuesta en este caso. 🙂
    • Estoy tratando de encontrar una manera de llevar a cabo el equilibrado llaves regex comprobar con escapar de llaves en el interior de las cadenas. E. G. el código siguiente paso: public class Foo { private const char BAR = '{'; private string _qux = "{{{"; } alguien Ha hecho esto?
    • Sólo se necesita añadir |'[^']*' en el lugar correcto: ejemplo. Si usted también necesita caracteres de escape, hay un ejemplo aquí: (Regex para la coincidencia de C# literales de cadena)[stackoverflow.com/a/4953878/7586].

Dejar respuesta

Please enter your comment!
Please enter your name here