Ayuda para arreglar una expresión regular de BBcode

Tengo una expresión regular que agarra las tags bbcode. Funciona muy bien a excepción de una pequeña falla.

Aquí está la expresión actual:

\[([^=\[\]]+)[=\x22']*([^ \[\]]*)['\x22]*\](.+)\[/\1\] 

Aquí hay un texto con el que coincide exitosamente y los grupos que construye:

[url = http: //www.google.com] ¡Vaya a google! [/ url]
1: url
2: http://www.google.com
3: ¡Ir a google!

[img] http://sofes.miximages.com/c%23/f [/ img]
1: img
2: NULL
3: http://sofes.miximages.com/c%23/f

[cita] [cita] primera cita anidada [/ cita] [cita] segunda cita anidada [/ cita] [/ cita]
1: cita
2: NULL
3: [cita] primera cita anidada [/ quote] [cita] segunda cita anidada [/ quote]

Todo esto es genial. Puedo manejar tags anidadas ejecutando el tercer grupo de coincidencia contra la misma expresión regular y manejar recursivamente todas las tags que están anidadas. El problema está en el ejemplo que usa las tags [quote]. Tenga en cuenta que el tercer grupo de coincidencias es un conjunto de dos tags de cotización, por lo que esperaríamos dos coincidencias. Sin embargo, tenemos un partido, como este:

[cita] primera cita anidada [/ quote] [cita] segunda cita anidada [/ quote]
1: cita
2: NULL
3: primera cita anidada [/ quote] [cita] segunda cita anidada

Ahhhh Eso no es lo que queríamos en absoluto. Hay una manera bastante simple de solucionarlo, modifico la expresión regular de esto:

 \[([^=\[\]]+)[=\x22']*([^ \[\]]*)['\x22]*\](.+)\[/\1\] 

A esto:

 \[([^=\[\]]+)[=\x22']*([^ \[\]]*)['\x22]*\](((?!\[/\1\]).)+)\[/\1\] 

Al agregar ((?!\[/\1\]).) Invalidamos toda la coincidencia si el tercer grupo de coincidencias contiene la etiqueta de cierre de BBcode. Así que ahora funciona, tenemos dos partidos:

[cita] primera cita anidada [/ quote] [cita] segunda cita anidada [/ quote]

[cita] primera cita anidada [/ cita]
1: cita
2: NULL
3: primera cita anidada

[cita] segunda cita anidada [/ cita]
1: cita
2: NULL 3: segunda cita anidada

Estaba feliz de que lo arreglaran, pero ahora tenemos otro problema. Esta nueva expresión regular falla en la primera donde anidamos las dos tags de cotización bajo una etiqueta de cotización más grande. Conseguimos dos partidos en lugar de uno:

[cita] [cita] primera cita anidada [/ cita] [cita] segunda cita anidada [/ cita] [/ cita]

[quote] [quote] primera cita anidada [/ quote]
1: cita
2: NULL
3: [cita] primera cita anidada

[cita] segunda cita anidada [/ cita]
1: cita
2: NULL
3: segunda cita anidada

La primera coincidencia es incorrecta y la segunda coincidencia, aunque está bien formada, no es una coincidencia deseada. Queríamos una coincidencia grande con el tercer grupo de coincidencia siendo las dos tags de comillas anidadas, como cuando usamos la primera expresión.

¿Alguna sugerencia? Siento que estoy tan cerca. Si puedo cruzar esta brecha, debería tener una expresión BBcode bastante poderosa.

Cualquier ayuda es apreciada.

Usando grupos de balanceo puedes construir una expresión regular como esta:

 (?> \[ (?[^][/=\s]+) \s* (?: = \s* (?[^][]*) \s*)? ] ) (? (?> \[(?[^][/=\s]+)[^][]*] | \[/(?<-innertag>\k)] | [^][]+ )* (?(innertag)(?!)) ) \[/\k] 

Simplificado según el ejemplo de Kobi.


En el siguiente:

 [foo=bar]baz[/foo] [b]foo[/b] [i][i][foo=bar]baz[/foo]foo[/i][/i] [i][i][i][i]foo[/i][/i][/i][i][i]foo[/i][/i][/i] [quote][quote][b][img]foo[/img][b]bold[/b][b][b]deep[/b][/b][/b][/quote]bar[quote]baz[/quote][/quote] 

Encuentra estas coincidencias:

  • [foo=bar]baz[/foo]
  • [b]foo[/b]
  • [i][i][foo=bar]baz[/foo]foo[/i][/i]
  • [i][i][i][i]foo[/i][/i][/i][i][i]foo[/i][/i][/i]
  • [quote][quote][b][img]foo[/img][b]bold[/b][b][b]deep[/b][/b][/b][/quote]bar[quote]baz[/quote][/quote]

Ejemplo completo en http://ideone.com/uULOs

(Versión antigua http://ideone.com/AXzxW )