2009-03-12 15 views
43

Ich versuche, eine Reihe von Dateien zu bearbeiten, und ich muss dann ändern, um irrelevante Informationen in den Dateinamen zu entfernen; Vor allem versuche ich, den Text in Klammern zu entfernen. Zum Beispiel:Wie kann ich Text in Klammern mit einem Regex entfernen?

filename = "Example_file_(extra_descriptor).ext" 

und ich möchte eine ganze Reihe von Dateien regex, wo der Klammerausdruck in der Mitte oder am Ende sein könnte, und variabler Länge.

Wie würde die Regex aussehen? Perl oder Python Syntax wäre bevorzugt.

+0

Sind Sie sicher, dass der "extra_descriptor" kein ")" enthalten kann? Wenn es geht, wird das Problem viel schwieriger ... – dmckee

+1

@dmckee: Es ist schwieriger, wenn die Parens * verschachtelt * werden können, obwohl wenn du nur alles zwischen dem ersten '(' und dem letzten ') loswerden willst nicht viel schwieriger: benutze einfach ein gieriges '. *' anstelle von '. *?'. –

+2

@j_random_hacker Sie haben Recht, es ist verdammt viel schwieriger, da geschachtelte Klammern nicht mit einer FSM erkannt werden können (Sie müssen die Verschachtelungsebene, die unbegrenzt ist, verfolgen) und daher nicht durch eine Regex. Damit es möglich ist, müssen Sie sich auf eine begrenzte Verschachtelung beschränken. – skyking

Antwort

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

So in Python, dann würden Sie tun:

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

gibt es irgendeinen Grund zu bevorzugen. *? über [^)] * – Kip

+1

@ J.F. Sebastian: Du hast Recht. –

+0

@Kip: nein. Ich weiß nicht warum, aber ... ist immer das Erste, was mir in den Sinn kommt. –

2

Wenn Sie sed verwenden stehen können (möglicherweise aus Ihrem Programm ausführen, es wäre so einfach sein wie:

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

Sie gruppieren nur den Ausdruck '. *'. – Gumbo

+0

@Gumbo: Nein, ist er nicht. In sed, "\\ (... \\") Gruppen. – runrig

+0

Ops, tut mir leid. Wusste das nicht. – Gumbo

19

ich würde verwenden:

\([^)]*\) 
3

Wenn ein Pfad enthält Klammern kann dann der r'\(.*?\)' regex ist nicht genug:

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) 

standardmäßig die Funktion eingeklammerten Brocken im Verzeichnis und Erweiterung Teilen des Weges bewahrt.

Beispiel:

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

Wenn Sie absolut keine regex verwenden müssen, Verwendung Perl mit berücksichtigen Text::Balanced die Klammer zu entfernen.

Sie denken vielleicht: "Warum all das, wenn eine Regex den Trick in einer Zeile macht?"

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

Text :: Balancierte Handles verschachtelte Klammern. So wird $filename = 'foo_(bar(baz)buz)).foo' richtig extrahiert. Die hier angebotenen Regex-basierten Lösungen schlagen bei dieser Zeichenfolge fehl. Der eine wird beim ersten schließenden paren anhalten und der andere wird sie alle essen.

$ filename = ~ s/([^}] *) //; # gibt 'foo_buz)) zurück. Foo'

$ filename = ~ s /(.*)//; # gibt ‚foo_.foo‘

# text ausgeglichen Beispiel gibt ‚foo _) foo‘

Wenn eine der regex Verhalten akzeptabel ist, verwenden Sie einen regulären Ausdruck - aber dokumentieren die Grenzen und die Annahmen gemacht werden .

+0

Während ich weiß, dass Sie verschachtelte Klammern mit (klassischen) Regexes nicht parsen können, wenn Sie wissen, dass Sie nie geschachtelte Klammern treffen werden, können Sie das Problem zu einem vereinfachen, das mit Regexes getan werden kann, und ziemlich einfach. Es ist Overkill, ein Parser-Tool zu verwenden, wenn wir es nicht brauchen. –

+0

@Chris Lutz - Ich hätte im ersten Satz eher "überlegen" als "verwenden" sollen. In vielen Fällen wird eine Regex die Aufgabe übernehmen, weshalb ich sagte, eine Regex zu verwenden, wenn das Verhalten akzeptabel ist. – daotoad

0

Java-Code:

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

Das Muster, das Teil in paretheses Spiele , die keine anderen ( und ) Zeichen zwischen (wie (xyz 123) in Text (abc(xyz 123)) ist

\([^()]*\) 

Einzelheiten:

  • \( - eine Öffnung runde Klammer (beachten Sie, dass in POSIX BRE, ( verwendet werden soll, sed Beispiel siehe unten)
  • [^()]* - null oder mehr (aufgrund der *Kleene star quantifier) Zeichen außer diejenigen, die in die negated character class/POSIX bracket expression, das heißt, irgendwelche Zeichen außer ( und )
  • \) - ein Schließrundbügel (kein entkommen in POSIX BRE erlaubt)

Entfernen Code-Schnipsel:

  • 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("\\([^()]*\\)", "")
  • Rubin: 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

Für diejenigen, die Python verwenden möchten, hier ist eine einfache Routine, die eingeklammerten Teil entfernt, einschließlich derjenigen mit verschachtelten Klammern. Okay, es ist keine Regex, aber es wird den Job machen!

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') 
Verwandte Themen