2009-12-23 30 views
6

Estoy tratando de eliminar el texto que está entre paréntesis (junto con los paréntesis mismos) pero tengo problemas con el escenario donde hay paréntesis entre paréntesis. Este es el método que estoy utilizando (en Ruby):Eliminar texto entre paréntesis (paréntesis entre paréntesis prob)

sentence.gsub(/\(.*?\)/, "") 

y que funciona bien hasta que tenga una oración como:

"This is (a test (string))" 

A continuación, los inductores anteriores. Alguien tiene alguna idea de cómo hacer esto? Estoy completamente perplejo.

+1

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

+0

No necesito explicar esta escena. – TenJack

Respuesta

10

Una approch es reemplazar los grupos entre paréntesis de adentro hacia afuera:

x = string.dup 
while x.gsub!(/\([^()]*\)/,""); end 
x 
10

Parece que tiene que ser codicioso, mediante la eliminación de la ?

>> "This is (a test (string))".gsub(/\(.*\)/, "") 
=> "This is " 

Eso hace que se vaya a la última ) en lugar de la primera. Sin embargo, no captura la anidación porque una expresión regular no puede hacer eso.

+1

No hace lo que debería para 'this is (entre paréntesis) y (así es esto) text';) – Juliet

+1

Escapar entre paréntesis nunca fue parte del problema; el OP hizo eso, pero las barras invertidas no aparecieron porque no aplicaba el formato correcto del código fuente. –

0

La respuesta de jleedev funcionará si solo hay un par de paréntesis en el nivel más externo; en ese caso, hacer que la expresión de las entrañas de esos paréntesis sea codiciosa debería hacer el truco.

Sin embargo, y tal vez un poco sorprendentemente, las expresiones regulares como se define en Perl, Java, Ruby y algunos otros idiomas, sino también grep y sed no son adecuados para hacer frente a este problema. No hay expresiones regulares para tratar el caso general de delimitadores anidados. Esta es una de las razones por las que las personas en SO le gritan cuando quiere usar una expresión regular para procesar HTML o XML.

Curiosamente, el creador del lenguaje Lua resolvió este problema agregando un nuevo patrón de coincidencia al lenguaje de patrones bastante simple. ¡Mira el puñado inferior de líneas en http://www.lua.org/pil/20.2.html!

+1

Los patrones recursivos de Perl pueden manejar delimitadores anidados. – newacct

+0

¡Uy! Reparado, gracias. –

1

La siguiente expresión regular Perl coincidirá con paréntesis balanceados:

/(\((?:[^\(\)]++|(?1))*\))/ 

Sin embargo, por el momento de llegar a este punto, usted no está técnicamente el uso de expresiones regulares "" más.

+3

Más al punto, tampoco estás usando Ruby. –

+0

¡eso es hermoso! Después de jugar con él encontré su versión de Ruby (1.9/Oniguruma):/(? \ ((?: [^ \ (\)] ++ | \ g ) * \)) / –

2

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 
Cuestiones relacionadas