2009-03-12 21 views
43

Próbuję obsłużyć kilka plików i muszę zmienić, aby usunąć zbędne informacje w nazwach plików; w szczególności, próbuję usunąć tekst w nawiasach. Na przykład:Jak mogę usunąć tekst w nawiasach za pomocą wyrażenia regularnego?

filename = "Example_file_(extra_descriptor).ext" 

i chcę regex całą masę plików gdzie nawias wyrażenie może być w środku lub na końcu, i o zmiennej długości.

Jak wyglądałby regex? Preferowana byłaby składnia Perla lub Pythona.

+0

Czy jesteś pewien, że "extra_descriptor" nie może zawierać znaku ")"? Jeśli to może problem staje się znacznie trudniejszy ... – dmckee

+1

@dmckee: Jest trudniej, jeśli pareny mogą być * zagnieżdżone *, ale jeśli chcesz po prostu pozbyć się wszystkiego między pierwszym ("i" ostatnim), to jest niewiele trudniej: po prostu użyj chciwego ". *" zamiast ". *?". –

+2

@j_random_hacker Masz rację, jest o wiele trudniej, ponieważ zagnieżdżone nawiasy nie mogą zostać rozpoznane za pomocą FSM (musisz śledzić poziom zagnieżdżenia, który jest nieograniczony), a więc nie przez wyrażenie regularne. Aby było możliwe, musisz ograniczyć się do ograniczonego poziomu zagnieżdżania. – skyking

Odpowiedz

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

Tak w Pythonie, można zrobić:

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

czy istnieje jakikolwiek powód do preferowania. *? ponad [^)] * – Kip

+1

@ J.F. Sebastian: masz rację. –

+0

@Kip: nope. Nie wiem dlaczego, ale. * Jest zawsze pierwszą rzeczą, która przychodzi mi do głowy. –

2

Jeśli można stać w użyciu sed (ewentualnie wykonać z poziomu programu, to byłoby tak proste, jak:

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

Po prostu grupujesz wyrażenie '. *'. – Gumbo

+0

@Gumbo: Nie, nie jest. W sed, "\\ (... \\)" grupy. – runrig

+0

Ops, przepraszam. Tego nie wiedziałem. – Gumbo

3

Jeśli ścieżka może zawierać nawiasy wtedy r'\(.*?\)' regex nie wystarczy:

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) 

Domyślnie funkcja zachowuje nawiasach kawałki w katalogu i przedłużających części ścieżki.

Przykład:

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

Jeśli nie absolutnie trzeba użyć regex, użycie rozważyć użycie Perl Text::Balanced usunąć nawias.

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

Może myślisz: "Dlaczego to wszystko, gdy regex wykonuje lewę w jednej linii?"

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

Tekst :: Otwory zagnieżdżone zagnieżdżone nawiasy. Tak więc $filename = 'foo_(bar(baz)buz)).foo' zostanie poprawnie wyodrębniony. Oferowane tu rozwiązania oparte na regex nie będą działać w tym łańcuchu. Ten zatrzyma się przy pierwszym zamknięciu, a drugi zje wszystkie.

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

$ filename = ~ s /(.*)//; # Zwraca „foo_.foo” „foo _) foo”

# tekst wyważony przykład zwraca

Jeśli któryś z regex zachowań jest akceptowalna, należy użyć wyrażenia regularnego - ale dokumentują ograniczenia i założenia są wykonane .Kod

+0

Chociaż wiem, że nie można przeanalizować zagnieżdżonego nawiasu za pomocą (klasycznych) wyrażeń regularnych, jeśli wiesz, że nigdy nie natkniesz się na nawiasy zagnieżdżone, możesz uprościć problem do takiego, który MOŻE być zrobiony z wyrażeń regularnych i dość łatwo. Przesadą jest używanie narzędzia analizatora składni, gdy go nie potrzebujemy. –

+0

@Chris Lutz - Powinienem był raczej "rozważyć" niż "używać" w pierwszym zdaniu. W wielu przypadkach regex wykona zadanie, dlatego zaleciłem użycie wyrażenia regularnego, jeśli zachowanie jest akceptowalne. – daotoad

0

Java:

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

Wzór, który pasuje podciągi w paretheses mających żadnych innych ( i ) znaki między (jak (xyz 123) w Text (abc(xyz 123)) jest

\([^()]*\) 

Szczegóły:

  • \( - okrągły nawias otwierający (zauważ, że w POSIX BRE, ( powinien być używany, patrz sed przykład poniżej)
  • [^()]* - zero lub więcej (ze względu na *Kleene star quantifier) znaków innych niż tych określonych w negated character class/POSIX bracket expression, to znaczy innych niż ( i )
  • \) znaków - zamykające okrągły wspornik (bez ucieczki POSIX BRE dozwolone)

Usuwanie fragmenty kodu:

  • 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, "%([^()]*%)", "")
  • atakujących/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

Dla tych, którzy chcą korzystać z Pythona, oto prosta rutyna, która usuwa podłańcuchów, w tym z zagnieżdżonymi nawiasami. Okay, to nie jest regex, ale wykona to zadanie!

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') 
Powiązane problemy