'Agh#$%#%2341-!zdrkfd'のような文字列を想像してみてください。この場合、小文字のみが返されるように操作を実行したいだけです(例として)。この場合は 'ghzdrkfdになります。 '。
Pythonでこれをどのように行いますか?明らかな方法は、文字のリスト「a」から「z」を作成し、文字列内の文字を繰り返し処理して、リスト内の文字のみの新しい文字列を文字ごとに作成することです。これは原始的なようです。
正規表現が適切かどうか疑問に思いました。不要な文字を置き換えるのは問題があるようで、ブラックリストよりもホワイトリストを好む傾向があります。 .match
関数は適切ではないようです。 Pythonサイトの適切なページを調べましたが、適切と思われる方法が見つかりませんでした。
正規表現が適切でなく、正しいアプローチがループしている場合、文字列をリストに「分解」する単純な関数はありますか?それとも、別のforループをヒットしているだけですか?
あなたが効率を探しているなら。 translate 関数を使用すると、取得できる最速です。
文字をすばやく置き換えたり、削除したりするために使用できます。
import string
delete_table = string.maketrans(
string.ascii_lowercase, ' ' * len(string.ascii_lowercase)
)
table = string.maketrans('', '')
"Agh#$%#%2341- -!zdrkfd".translate(table, delete_table)
In python 2.6:2番目のテーブルはもう必要ありません
import string
delete_table = string.maketrans(
string.ascii_lowercase, ' ' * len(string.ascii_lowercase)
)
"Agh#$%#%2341- -!zdrkfd".translate(None, delete_table)
これは、他のどの方法よりもはるかに高速な方法です。もちろん、delete_tableをどこかに保存して使用する必要があります。ただし、保存して毎回ビルドしなくても、これまでに提案された他の方法よりも高速になります。
ここで私の主張を確認するために、結果は次のとおりです。
for i in xrange(10000):
''.join(c for c in s if c.islower())
real 0m0.189s
user 0m0.176s
sys 0m0.012s
正規表現ソリューションの実行中:
for i in xrange(10000):
re.sub(r'[^a-z]', '', s)
real 0m0.172s
user 0m0.164s
sys 0m0.004s
[リクエストに応じて]正規表現をプリコンパイルする場合:
r = re.compile(r'[^a-z]')
for i in xrange(10000):
r.sub('', s)
real 0m0.166s
user 0m0.144s
sys 0m0.008s
Translateメソッドを同じ回数実行した場合:
real 0m0.075s
user 0m0.064s
sys 0m0.012s
s = 'Agh#$%#%2341- -!zdrkfd'
print ''.join(c for c in s if c.islower())
文字列オブジェクトは反復可能です。文字列をリストに「分解」する必要はありません。リスト内包表記には任意の条件を設定でき、それに応じて文字がフィルタリングされます。
正規表現を使用してこれを実装することもできますが、これはループを非表示にするだけです。正規表現ライブラリは、文字列をフィルタリングするために、文字列の文字をループする必要があります。
正規表現の使用は、特にこのシナリオでは十分に簡単です。
>>> import re
>>> s = 'ASDjifjASFJ7364'
>>> re.sub(r'[^a-z]+', '', s)
'jifj'
これを何度も行う予定がある場合は、事前に正規表現をコンパイルすることをお勧めします。
>>> import re
>>> s = 'ASDjifjASFJ7364'
>>> r = re.compile(r'[^a-z]+')
>>> r.sub('', s)
'jifj'
s = 'ASDjifjASFJ7364'
s_lowercase = ''.join(filter(lambda c: c.islower(), s))
print s_lowercase #print 'jifj'
>>> s = 'Agh#$%#%2341- -!zdrkfd'
>>> ''.join(i for i in s if i in 'qwertyuiopasdfghjklzxcvbnm')
'ghzdrkfd'
inputstring
を取得し、それをwhitelist
の文字に対してフィルタリングする、より一般的で理解しやすいソリューション:
inputstring = "Agh#$%#%2341- -!zdrkfd"
whitelist = "abcdefghijklmnopqrstuvwxyz"
remove = inputstring.translate(None, whitelist)
result = inputstring.translate(None, remove)
print result
このプリント
ghzdrkfd
最初 string.translate
は、入力文字列からホワイトリスト内のすべての文字を削除します。これにより、削除したい文字が得られます。二番目 string.translate
callは、入力文字列からそれらを削除し、目的の結果を生成します。
文字列の操作に特に関心がある場合の1つの解決策は次のとおりです。
s = 'Agh#$%#%2341- -!zdrkfd'
lowercase_chars = [chr(i) for i in xrange(ord('a'), ord('z') + 1)]
whitelist = set(lowercase_chars)
filtered_list = [c for c in s if c in whitelist]
ホワイトリストは、実際には効率のためのセット(リストではありません)です。
文字列が必要な場合は、join()を使用します。
filtered_str = ''.join(filtered_list)
filter()は、より一般的なソリューションです。ドキュメントから( http://docs.python.org/library/functions.html ):
filter(関数、反復可能)
関数がtrueを返すiterableの要素からリストを作成します。 iterableは、シーケンス、反復をサポートするコンテナー、またはイテレーターのいずれかです。 iterableが文字列またはタプルの場合、結果にもそのタイプがあります。それ以外の場合は常にリストです。関数がNoneの場合、恒等関数が想定されます。つまり、falseであるiterableのすべての要素が削除されます。
これは、filter()を使用する1つの方法です。
filtered_list = filter(lambda c: c.islower(), s)
import string
print filter(string.lowercase.__contains__, "lowerUPPER")
print filter("123".__contains__, "a1b2c3")
正規表現を使用します。小文字の一致[a-z]の場合。
import string
print "".join([c for c in "Agh#$%#%2341- -!zdrkfd" if c in string.lowercase])