2013-07-24 8 views
13

変換文字列を生の文字列リテラルに変換する記事がありますが、それらのどれも私の状況には役立ちません。ユーザ入力文字列を生の文字列リテラルに変換して正規表現を作成する

私の問題は、次のとおりです。

言ってやるが、例えば、私はパターン「\セクションでは、」テキスト「ABCD \ sectiondefghi」であるかどうかを知りたいです。もちろん、私はこれを行うことができます:

import re 

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

それは私が欲しいものを私に与えるでしょう。しかし、新しいテキストで新しいパターンを見つけるたびに、痛いコードを変更する必要があります。したがって、私はこのような、より柔軟なもの(test.pyを)書きたい:

import re 
import sys 

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

その後、私はこのようなターミナルでそれを実行したい:

python test.py \\section abcd\sectiondefghi 

しかし、動作しないこと(私は\\\\sectionを使うのが嫌です)。

私のユーザー入力(端末またはファイルから)をPythonの生の文字列に変換する方法はありますか?あるいは、ユーザー入力から正規表現パターンのコンパイルを行う良い方法がありますか?

ありがとうございました。

答えて

20

使用re.escape()入力テキストを正規表現でリテラルテキストとして扱われていることを確認する:

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

デモ:

>>> 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()は、すべての非英数字をエスケープ。それぞれのそのような文字の前にバックスラッシュを追加:これを行うには

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

一方、リテラル文字列を検索している場合、reは間違ったツールです。 – Fredrik

+0

@Fredrik:私はこれがより大きなパターンの一部となり、OPが単純化されたと仮定していました。 –

+0

@MartijnPietersありがとう、re.escapeが本当に役立ちます! – dbrg77

3

一つの方法は、optparseまたはargparseのように、引数パーサを使用しています。

あなたのコードは次のようになります:

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) 

それを使用して私の例:

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

あなたの例の使用:だから明確にすることが

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

を、あなたが検索するもの(あなたの例では "\ section")は正規表現かリテラル文字列ですか?後者の場合、reモジュールは本当にタスクの正しいツールではありません。検索文字列needleとターゲット文字列haystackを与え、あなたが行うことができます:正規表現ベースのバージョンよりも効率的

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

すべてが。

re.escapeは、実行時に大規模な正規表現にリテラルフラグメントを挿入する必要がある場合にはまだ役に立ちますが、re.compile(re.escape(needle))になると、ほとんどの場合、タスク用のツールが改善されます。

EDIT:ここでの本当の問題は、シェルのエスケープルールです。これはPythonや生の文字列とは関係ありません。

python test.py \\section abcd\sectiondefghi 

をUnixスタイルのシェルにPythonはそれを見る前に、「\セクション」部分は、シェルによって「\部」に変換されます。つまり、入力した場合、です。

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

は、比較対照:

$ 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 

(明示的にプリントを使用してその問題を解決する最も簡単な方法は、あなたが単一引用符内の引数を入れていますが、これはアンエスケープをスキップするようにシェルに伝えることですここで結合された文字列は、reprを避けるためにさらに混乱を招く...)

関連する問題