El problema con esto es que las lenguas que contienen paréntesis anidados (o de hecho nada anidado, OIA todo lo que requiere la repetición) no son regular, están al menos libres de contexto. Esto significa que no pueden ser descritos por una gramática regular. Las expresiones regulares son una notación compacta para gramáticas regulares. Ergo, los paréntesis anidados no se pueden describir con expresiones regulares.
Sin embargo, no estamos hablando de expresiones regulares aquí, estamos hablando de Regexp
s. Si bien su semántica y sintaxis se basan (muy) libremente en expresiones regulares, son bastante diferentes y especialmente mucho más poderosas. Dependiendo del sabor particular de Regexp
que use, pueden o no ser capaces de expresar la recursividad y, por lo tanto, analizar paréntesis anidados. Perl Regex
, por ejemplo puede parse anidado paréntesis.No estoy seguro de si Ruby's Regexp
puede, pero realmente no me importa, porque la forma en que Regexp
son más poderosas que las expresiones regulares generalmente se logra atornillando más y más sintaxis en ellos.
Esto convierte expresiones regulares, que están diseñadas para ser simples, en monstruos incomprensibles. (Si puede ver de un vistazo lo que el Perl Regex
publicado por @Anon hace, entonces pruébelo. Pero no puedo y por lo tanto prefiero no usarlo)
Prefiero usar un analizador más potente, en lugar de un complejo Regexp
.
En este caso, tiene un lenguaje sin contexto, por lo tanto, puede utilizar un analizador de bajadas recursivo muy simple. Puede simplificar aún más su analizador de descenso recursivo manejando aquellas subpartes que son regulares con una expresión regular. Por último, si se reemplaza la recursividad en el analizador sintáctico descendente recursivo con iteración + mutación y hacer un uso inteligente de la semántica booleanas de Ruby, todo el analizador obtiene básicamente condensa a esta sola línea:
while str.gsub!(/\([^()]*?\)/, ''); end
Qué no creo es muy malo
Aquí está toda la cosa con un poco de extracción extra de espacio en blanco por duplicado y (por supuesto) un conjunto de pruebas:
require 'test/unit'
class TestParenthesesRemoval < Test::Unit::TestCase
def test_that_it_removes_even_deeply_nested_parentheses
str = 'This is (was?) some ((heavily) parenthesized (but not overly so
(I hope))) text with (superflous) parentheses:)(.'
res = 'This is some text with parentheses:)(.'
while str.gsub!(/\([^()]*?\)/, ''); end
str.squeeze!(' ')
assert_equal res, str
end
end
Qué pasa si hay un número desigual de las etiquetas de apertura y cierre, como en '(foo) bar) 'o si no hay pares como en' foo) (bar'? – Gumbo
No necesito explicar esta escena. – TenJack