2009-03-12 48 views
43

Estoy tratando de manejar un montón de archivos, y necesito modificarlos para eliminar información extraña en los nombres de los archivos; en particular, estoy tratando de eliminar el texto entre paréntesis. Por ejemplo:¿Cómo puedo eliminar texto entre paréntesis con una expresión regular?

filename = "Example_file_(extra_descriptor).ext" 

y quiero regex un montón de archivos en donde la expresión entre paréntesis podría introducirse en la mitad o al final, y de longitud variable.

¿Cómo sería la expresión regular? Sería preferible la sintaxis de Perl o Python.

+0

¿Estás seguro de que el "extra_descriptor" no puede incluir un ")"? Si puede, el problema se vuelve mucho más difícil ... – dmckee

+1

@dmckee: es más difícil si los pares pueden * anidar *, aunque si solo quieres deshacerte de todo entre el primero '(' y el último ')' es no mucho más difícil: simplemente use un codicioso '. *' en lugar de '. *?'. –

+2

@j_random_hacker Estás en lo correcto, es mucho más difícil ya que los paréntesis anidados no se pueden reconocer con un FSM (tienes que hacer un seguimiento del nivel de anidación que es ilimitado) y por lo tanto no con una expresión regular. Para que sea posible, debe restringirse a un nivel limitado de anidación. – skyking

Respuesta

73
s/\([^)]*\)// 

Así que en Python, que harías:

re.sub(r'\([^)]*\)', '', filename) 
+1

¿hay alguna razón para preferir. *? sobre [^)] * – Kip

+1

@ J.F. Sebastian: tienes razón. –

+0

@Kip: no. No sé por qué, pero. * Siempre es lo primero que se me viene a la mente. –

2

Si puedes soportar a utilizar sed (posiblemente ejecutar desde dentro de su programa, que sería tan simple como:

sed 's/(.*)//g' 
+0

Usted solo está agrupando la expresión '. *'. – Gumbo

+0

@Gumbo: No, no lo es. En sed, "\\ (... \\)" grupos. – runrig

+0

Ops, lo siento. No lo sabía – Gumbo

19

yo usaría:

\([^)]*\) 
3

Si una ruta puede contener paréntesis, a continuación, el r'\(.*?\)' expresión regular no es suficiente:

import os, re 

def remove_parenthesized_chunks(path, safeext=True, safedir=True): 
    dirpath, basename = os.path.split(path) if safedir else ('', path) 
    name, ext = os.path.splitext(basename) if safeext else (basename, '') 
    name = re.sub(r'\(.*?\)', '', name) 
    return os.path.join(dirpath, name+ext) 

Por defecto la función conserva trozos entre paréntesis en el directorio y ampliación partes del camino.

Ejemplo:

>>> f = remove_parenthesized_chunks 
>>> f("Example_file_(extra_descriptor).ext") 
'Example_file_.ext' 
>>> path = r"c:\dir_(important)\example(extra).ext(untouchable)" 
>>> f(path) 
'c:\\dir_(important)\\example.ext(untouchable)' 
>>> f(path, safeext=False) 
'c:\\dir_(important)\\example.ext' 
>>> f(path, safedir=False) 
'c:\\dir_\\example.ext(untouchable)' 
>>> f(path, False, False) 
'c:\\dir_\\example.ext' 
>>> f(r"c:\(extra)\example(extra).ext", safedir=False) 
'c:\\\\example.ext' 
0
>>> import re 
>>> filename = "Example_file_(extra_descriptor).ext" 
>>> p = re.compile(r'\([^)]*\)') 
>>> re.sub(p, '', filename) 
'Example_file_.ext' 
5

Si no absolutamente necesario utilizar una expresión regular, uso considerar el uso de Perl Text::Balanced para eliminar los paréntesis.

use Text::Balanced qw(extract_bracketed); 

my ($extracted, $remainder, $prefix) = extract_bracketed($filename, '()', '[^(]*'); 

{ no warnings 'uninitialized'; 

    $filename = (defined $prefix or defined $remainder) 
       ? $prefix . $remainder 
       : $extracted; 
} 

Usted puede estar pensando, "¿Por qué hacer todo esto cuando una expresión regular hace el truco en una línea?"

$filename =~ s/\([^}]*\)//; 

Text :: Balanced handles nested parenthesis. Por lo tanto, $filename = 'foo_(bar(baz)buz)).foo' se extraerá correctamente. Las soluciones basadas en expresiones regulares que se ofrecen aquí fallarán en esta cadena. El uno se detendrá en la primera reunión de padres, y el otro se los comerá a todos.

$ filename = ~ s/([^}] *) //; # devuelve 'foo_buz)). Foo'

$ filename = ~ s /(.*)//; # devuelve 'foo_.foo' 'foo _) foo'

# texto equilibrado ejemplo retornos

Si cualquiera de los comportamientos de expresiones regulares es aceptable, utilice una expresión regular - pero documentar las limitaciones y los supuestos que se hizo .código

+0

Aunque sé que no puede analizar paréntesis anidados con expresiones regulares (clásicas), si sabe que nunca encontrará paréntesis anidados, puede simplificar el problema a uno que PUEDE hacerse con expresiones regulares, y con bastante facilidad. Es excesivo usar una herramienta analizadora cuando no la necesitamos. –

+0

@Chris Lutz - Debería haber dicho "considerar" en lugar de "usar" en la primera oración. En muchos casos, una expresión regular hará el trabajo, por eso dije usar una expresión regular si el comportamiento es aceptable. – daotoad

0

Java:

Pattern pattern1 = Pattern.compile("(\\_\\(.*?\\))"); 
System.out.println(fileName.replace(matcher1.group(1), "")); 
9

El patrón que coincida con subcadenas en paretheses que no tienen otros ( y ) caracteres en el medio (como (xyz 123) en Text (abc(xyz 123)) es

\([^()]*\) 

detalles:

  • \( - una abertura redonda soporte (tenga en cuenta que, en POSIX BRE, ( debe ser utilizado, ver sed ejemplo a continuación)
  • [^()]* - cero o más (debido a las *Kleene star quantifier) caracteres distintos de los definidos en la negated character class/POSIX bracket expression, es decir, cualquier caracteres distintos de ( y )
  • \) - un soporte redondo de cierre (no se escape en POSIX BRE permitido)

Extracción de fragmentos de código:

  • JavaScript: string.replace(/\([^()]*\)/g, '')
  • PHP: preg_replace('~\([^()]*\)~', '', $string)
  • Perl: $s =~ s/\([^()]*\)//g
  • Python: re.sub(r'\([^()]*\)', '', s)
  • C#: Regex.Replace(str, @"\([^()]*\)", string.Empty)
  • VB.NET: Regex.Replace(str, "\([^()]*\)", "")
  • Java: s.replaceAll("\\([^()]*\\)", "")
  • Rubí: s.gsub(/\([^()]*\)/, '')
  • R: gsub("\\([^()]*\\)", "", x)
  • Lua: string.gsub(s, "%([^()]*%)", "")
  • Bash/sed: sed 's/([^()]*)//g'
  • Tcl: regsub -all {\([^()]*\)} $s "" result
  • C++ std::regex: std::regex_replace(s, std::regex(R"(\([^()]*\))"), "")
  • Objective-C:
    NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"\\([^()]*\\)" options:NSRegularExpressionCaseInsensitive error:&error]; NSString *modifiedString = [regex stringByReplacingMatchesInString:string options:0 range:NSMakeRange(0, [string length]) withTemplate:@""];
0

Para aquellos que quieran utilizar Python, he aquí una rutina simple que elimina las subcadenas entre paréntesis, incluyendo aquellos con paréntesis anidados. De acuerdo, no es una expresión regular, ¡pero hará el trabajo!

def remove_nested_parens(input_str): 
    """Returns a copy of 'input_str' with any parenthesized text removed. Nested parentheses are handled.""" 
    result = '' 
    paren_level = 0 
    for ch in input_str: 
     if ch == '(': 
      paren_level += 1 
     elif (ch == ')') and paren_level: 
      paren_level -= 1 
     elif not paren_level: 
      result += ch 
    return result 

remove_nested_parens('example_(extra(qualifier)_text)_test(more_parens).ext') 
Cuestiones relacionadas