Wie kann ich Text in Klammern mit einem regulären Ausdruck entfernen?

77

Ich versuche, eine Reihe von Dateien zu verarbeiten, und ich muss sie dann ändern, um überflüssige Informationen in den Dateinamen zu entfernen. Insbesondere versuche ich, Text in Klammern zu entfernen. Zum Beispiel:

filename = "Example_file_(extra_descriptor).ext"

und ich möchte eine ganze Reihe von Dateien neu ausdrücken, wobei der Ausdruck in Klammern in der Mitte oder am Ende stehen kann und von variabler Länge ist.

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

Technischer Barde
quelle
Sind Sie sicher, dass der "extra_descriptor" kein ")" enthalten kann? Wenn es geht, wird das Problem viel schwieriger ...
dmckee --- Ex-Moderator Kätzchen
1
@dmckee: Es ist schwieriger, wenn die Parens verschachtelt werden können. Wenn Sie jedoch nur alles zwischen dem ersten '(' und dem letzten ')' loswerden möchten, ist es nicht viel schwieriger: Verwenden Sie stattdessen ein gieriges '. *' '. *?'.
j_random_hacker
2
@j_random_hacker Sie haben Recht, es ist verdammt viel schwieriger, da verschachtelte Klammern mit einem FSM nicht erkannt werden können (Sie müssen die unbegrenzte Verschachtelungsebene verfolgen) und daher nicht mit einem regulären Ausdruck. Damit dies möglich ist, müssen Sie sich auf ein begrenztes Verschachtelungsniveau beschränken.
Skyking

Antworten:

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

In Python würden Sie also Folgendes tun:

re.sub(r'\([^)]*\)', '', filename)
Kann Berk Güder
quelle
2
Gibt es einen Grund zu bevorzugen. *? über [^)] *
Kip
@ Kip: Nein. Ich weiß nicht warum, aber. * Ist immer das erste, was mir in den Sinn kommt.
Kann Berk Güder
@Kip :. *? wird nicht von allen Regex-Parsern behandelt, während Ihr [^)] * von fast allen behandelt wird.
X-Istence
@Kip: Ein weiterer Grund ist das Backtracking.
Gumbo
13
. * erhält alles zwischen dem ersten linken und dem letzten rechten Paren: 'a (b) c (d) e' wird zu 'ae'. [^)] * entfernt nur zwischen dem ersten linken und dem ersten rechten Paren: 'ac (d) e'. Sie erhalten auch unterschiedliche Verhaltensweisen für verschachtelte Parens.
Daotoad
66

Das Muster, das Teilzeichenfolgen in Klammern ohne andere (und )dazwischen liegende Zeichen (wie (xyz 123)in Text (abc(xyz 123)) entspricht, ist

\([^()]*\)

Details :

Codefragmente entfernen:

  • 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("\\([^()]*\\)", "")
  • Ruby :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"(\([^()]*\))"), "")
  • Ziel-C :
    NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"\\([^()]*\\)" options:NSRegularExpressionCaseInsensitive error:&error]; NSString *modifiedString = [regex stringByReplacingMatchesInString:string options:0 range:NSMakeRange(0, [string length]) withTemplate:@""];
  • Swift :s.replacingOccurrences(of: "\\([^()]*\\)", with: "", options: [.regularExpression])
Wiktor Stribiżew
quelle
21

Ich würde ... benutzen:

\([^)]*\)
Gumbo
quelle
6

Wenn Sie nicht unbedingt einen regulären Ausdruck verwenden müssen, sollten Sie Perls Text :: Balanced verwenden , um die Klammern zu entfernen.

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

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

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

Text :: Balanced behandelt verschachtelte Klammern. Also $filename = 'foo_(bar(baz)buz)).foo'wird 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' zurück

# text balanciertes Beispiel gibt 'foo _) zurück. foo'

Wenn eines der Regex-Verhaltensweisen akzeptabel ist, verwenden Sie einen Regex - dokumentieren Sie jedoch die Einschränkungen und die getroffenen Annahmen.

daotoad
quelle
Ich weiß zwar, dass Sie verschachtelte Klammern nicht mit (klassischen) regulären Ausdrücken analysieren können, aber wenn Sie wissen, dass Sie niemals auf verschachtelte Klammern stoßen werden, können Sie das Problem zu einem Problem vereinfachen, das mit regulären Ausdrücken und ziemlich einfach durchgeführt werden kann. Es ist übertrieben, ein Parser-Tool zu verwenden, wenn wir es nicht benötigen.
Chris Lutz
@ Chris Lutz - Ich hätte im ersten Satz eher "Überlegen" als "Verwenden" sagen sollen. In vielen Fällen erledigt ein Regex die Aufgabe, weshalb ich sagte, einen Regex zu verwenden, wenn das Verhalten akzeptabel ist.
Daotoad
3

Wenn ein Pfad Klammern enthalten kann, reicht der r'\(.*?\)'reguläre Ausdruck nicht aus:

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 behält die Funktion Klammern in Klammern in Verzeichnis- und Erweiterungsteilen des Pfads bei.

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'
jfs
quelle
2

Für diejenigen, die Python verwenden möchten, ist hier eine einfache Routine, die in Klammern gesetzte Teilzeichenfolgen entfernt, einschließlich solcher mit verschachtelten Klammern. Okay, es ist kein regulärer Ausdruck, 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')
Andrew Basile
quelle
Ich wollte schon selbst verschachtelte Klammern entfernen, aber Sie sparen meine Zeit, danke! 😊
AivanF.
1

Wenn Sie es verwenden können sed(möglicherweise aus Ihrem Programm heraus ausführen), ist dies so einfach wie:

sed 's/(.*)//g'
Samoz
quelle
Sie gruppieren nur den Ausdruck .*.
Gumbo
@ Gumbo: Nein, ist er nicht. In sed "\ (... \)" Gruppen.
Runrig
Ops, sorry. Wusste das nicht.
Gumbo
0
>>> import re
>>> filename = "Example_file_(extra_descriptor).ext"
>>> p = re.compile(r'\([^)]*\)')
>>> re.sub(p, '', filename)
'Example_file_.ext'
Riza
quelle
0

Java-Code:

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