2013-07-24 11 views
13

So che ci sono alcuni post sulla conversione da stringa a stringa raw, ma nessuno di essi aiuta la mia situazione.Converti stringhe di input dell'utente in stringhe non formattate per creare espressioni regolari

Il mio problema è:

Diciamo, per esempio, voglio sapere se la "\ sezione" modello è nel testo "abcd \ sectiondefghi". Certo, posso farlo:

import re 

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

Questo mi darà quello che voglio. Tuttavia, ogni volta che voglio trovare un nuovo modello in un nuovo testo, devo cambiare il codice che è doloroso. Pertanto, voglio scrivere qualcosa di più flessibile, come questo (test.py):

import re 
import sys 

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

Poi, voglio correre in terminale come questo:

python test.py \\section abcd\sectiondefghi 

Tuttavia, ciò non funzionerà (Odio usare \\\\section).

Quindi, c'è un modo per convertire il mio input utente (da terminale o da file) a stringa raw Python? O c'è un modo migliore di fare la compilazione del pattern di espressioni regolari dall'input dell'utente?

Grazie mille.

risposta

20

Usa re.escape() per assicurarsi che il testo di input viene trattato come testo letterale in un'espressione regolare:

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() sfugge tutti i non-alfanumerici; aggiungendo una barra rovesciata davanti a ciascun carattere come:

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

D'altra parte, se stai cercando stringhe letterali, re è lo strumento sbagliato. – Fredrik

+0

@Fredrik: stavo dando per scontato che questo sarebbe stato parte di uno schema più ampio e l'OP semplicemente semplificato. –

+0

@MartijnPieters Grazie, il re.escape aiuta davvero! – dbrg77

3

Un modo per farlo è usare un parser argomento, come optparse o argparse.

Il codice dovrebbe essere simile a questa:

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) 

Un esempio di me usarlo:

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

Usando il tuo esempio:

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

Quindi, solo per essere chiari, è la cosa che cerchi ("\ section" nel tuo esempio) che dovrebbe essere un'espressione regolare o una stringa letterale? Se quest'ultimo, il modulo re non è realmente lo strumento giusto per l'attività; data una stringa di ricerca needle e una stringa di destinazione haystack, si può fare:

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

che sono tutti più efficiente rispetto alla versione regexp-based.

re.escape è ancora utile se è necessario inserire un frammento letterale in un regexp più grande in fase di esecuzione, ma se si finisce per fare re.compile(re.escape(needle)), ci sono per la maggior parte dei casi migliori strumenti per l'attività.

EDIT: Sto iniziando a sospettare che il vero problema qui è le regole di escape della shell, che non ha nulla a che fare con Python o stringhe non elaborate. Cioè, se si digita:

python test.py \\section abcd\sectiondefghi 

in un guscio in stile Unix, la parte "\ sezione" viene convertito "\ sezione" dalla shell per, prima di Python vede. Il modo più semplice per risolvere il problema che è quello di raccontare la shell di saltare unescaping, che si può fare mettendo l'argomento all'interno apici:

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

confrontare e contrapporre:

$ 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 

(esplicitamente tramite stampa su una stringa unita qui per evitare repr aggiungendo ancora più confusione ...)

Problemi correlati