2013-07-24 7 views
13

Wiem, że istnieją pewne posty dotyczące konwersji ciągów do surowych literałów łańcuchowych, ale żadna z nich nie pomaga w mojej sytuacji.Konwertuj ciągi wejściowe użytkownika na nieprzetworzone ciągi znaków w celu skonstruowania wyrażenia regularnego

Mój problem jest:

Załóżmy na przykład, chcę wiedzieć, czy wzór "\ section" w tekście "abcd \ sectiondefghi". Oczywiście, mogę to zrobić:

import re 

motif = r"\\section" 
txt = r"abcd\sectiondefghi" 
pattern = re.compile(motif) 
print pattern.findall(txt) 

To da mi to, czego chcę. Jednak za każdym razem, gdy chcę znaleźć nowy wzór w nowym tekście, muszę zmienić kod, który jest bolesny. Dlatego chcę napisać coś bardziej elastyczny, tak (test.py):

import re 
import sys 

motif = sys.argv[1] 
txt = sys.argv[2] 
pattern = re.compile(motif) 
print pattern.findall(txt) 

Następnie chcę go uruchomić w terminalu tak:

python test.py \\section abcd\sectiondefghi 

jednak, że nie będzie działać (Nienawidzę używać \\\\section).

Czy jest jakiś sposób na konwersję moich danych wejściowych użytkownika (z terminala lub z pliku) na pytony nieprzetworzony ciąg znaków? Czy istnieje lepszy sposób na kompilację wzorca regularnego z danych wprowadzanych przez użytkownika?

Dziękuję bardzo.

Odpowiedz

20

Zastosowanie re.escape() aby upewnić tekst wejściowy jest traktowany jako tekst dosłowny w wyrażeniu regularnym:

pattern = re.compile(re.escape(motif)) 

Demo:

>>> import re 
>>> motif = r"\section" 
>>> txt = r"abcd\sectiondefghi" 
>>> pattern = re.compile(re.escape(motif)) 
>>> txt = r"abcd\sectiondefghi" 
>>> print pattern.findall(txt) 
['\\section'] 

re.escape() ucieka wszystkie Pomieszczenia znaki alfanumeryczne; dodając odwrotny ukośnik przed każdym takim charakterze:

>>> re.escape(motif) 
'\\\\section' 
>>> re.escape('\n [hello world!]') 
'\\\n\\ \\[hello\\ world\\!\\]' 
+1

Z drugiej strony, jeśli szukasz literałów, re jest niewłaściwym narzędziem. – Fredrik

+0

@Fredrik: Zakładałem, że to będzie część większego wzorca, a PO po prostu uproszczony. –

+0

@MartijnPieters Dziękuję, re.escape naprawdę pomaga! – dbrg77

3

Jednym ze sposobów, aby to zrobić jest użycie parsera argumentu, jak optparse lub argparse.

Twój kod będzie wyglądać następująco:

import re 
from optparse import OptionParser 

parser = OptionParser() 
parser.add_option("-s", "--string", dest="string", 
        help="The string to parse") 
parser.add_option("-r", "--regexp", dest="regexp", 
        help="The regular expression") 
parser.add_option("-a", "--action", dest="action", default='findall', 
        help="The action to perform with the regexp") 

(options, args) = parser.parse_args() 

print getattr(re, options.action)(re.escape(options.regexp), options.string) 

Przykładem mnie używając go:

> code.py -s "this is a string" -r "this is a (\S+)" 
['string'] 

Korzystanie przykład:

> code.py -s "abcd\sectiondefghi" -r "\section" 
['\\section'] 
# remember, this is a python list containing a string, the extra \ is okay. 
0

Więc po prostu być jasne, czy to, czego szukasz ("\ section" w twoim przykładzie) powinno być wyrażeniem regularnym lub literalnym? Jeśli to drugie, moduł re nie jest właściwym narzędziem do tego zadania; dany ciąg wyszukiwania needle i łańcuch docelowy haystack, można zrobić:

# is it in there 
needle in haystack 

# how many copies are there 
n = haystack.count(needle) 
python test.py \\section abcd\sectiondefghi 
# where is it 
ix = haystack.find(needle) 

z których wszystkie są bardziej wydajne niż wersja regexp oparte.

re.escape jest nadal przydatny, jeśli trzeba wstawić literalny fragment do większego wyraŜenia regularnego w czasie wykonywania, ale jeśli kończy się to na wykonaniu re.compile(re.escape(needle)), w większości przypadków istnieją lepsze narzędzia do tego zadania.

EDYCJA: Zaczynam podejrzewać, że prawdziwym problemem są tutaj reguły ucieczki powłoki, które nie mają nic wspólnego z Python lub surowymi ciągami. Oznacza to, że jeśli wpiszesz:

python test.py \\section abcd\sectiondefghi 

w powłoce Unix stylu, w „\ section” część przekształca się „rozdział \” przez powłokę, zanim Python widzi. Najprostszym sposobem, aby naprawić to powiedzieć skorupę pominąć unescaping, co można zrobić, umieszczając argumentu wewnątrz pojedynczych cudzysłowów:

python test.py '\\section' 'abcd\sectiondefghi' 

porównać i kontrast:

$ python -c "import sys; print ','.join(sys.argv)" test.py \\section abcd\sectiondefghi 
-c,test.py,\section,abcdsectiondefghi 

$ python -c "import sys; print ','.join(sys.argv)" test.py '\\section' 'abcd\sectiondefghi' 
-c,test.py,\\section,abcd\sectiondefghi 

(jawnie przy użyciu druku na połączony ciąg tutaj, aby uniknąć repr dodając jeszcze więcej dezorientacji ...)

Powiązane problemy