web-dev-qa-db-ja.com

リスト内の文字のみが返されるように文字列をフィルタリングするにはどうすればよいですか?

'Agh#$%#%2341-!zdrkfd'のような文字列を想像してみてください。この場合、小文字のみが返されるように操作を実行したいだけです(例として)。この場合は 'ghzdrkfdになります。 '。

Pythonでこれをどのように行いますか?明らかな方法は、文字のリスト「a」から「z」を作成し、文字列内の文字を繰り返し処理して、リスト内の文字のみの新しい文字列を文字ごとに作成することです。これは原始的なようです。

正規表現が適切かどうか疑問に思いました。不要な文字を置き換えるのは問題があるようで、ブラックリストよりもホワイトリストを好む傾向があります。 .match関数は適切ではないようです。 Pythonサイトの適切なページを調べましたが、適切と思われる方法が見つかりませんでした。

正規表現が適切でなく、正しいアプローチがループしている場合、文字列をリストに「分解」する単純な関数はありますか?それとも、別のforループをヒットしているだけですか?

22
MetaHyperBolic

あなたが効率を探しているなら。 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
32
Nadia Alramli
s = 'Agh#$%#%2341- -!zdrkfd'  
print ''.join(c for c in s if c.islower())

文字列オブジェクトは反復可能です。文字列をリストに「分解」する必要はありません。リスト内包表記には任意の条件を設定でき、それに応じて文字がフィルタリングされます。

正規表現を使用してこれを実装することもできますが、これはループを非表示にするだけです。正規表現ライブラリは、文字列をフィルタリングするために、文字列の文字をループする必要があります。

18
Ayman Hourieh

正規表現の使用は、特にこのシナリオでは十分に簡単です。

>>> 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'
5
s = 'ASDjifjASFJ7364'
s_lowercase = ''.join(filter(lambda c: c.islower(), s))
print s_lowercase #print 'jifj'
4
Jason Coon
>>> s = 'Agh#$%#%2341- -!zdrkfd'
>>> ''.join(i for i in s if  i in 'qwertyuiopasdfghjklzxcvbnm')
'ghzdrkfd'
4
Nixuz

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は、入力文字列からそれらを削除し、目的の結果を生成します。

2
Rolf

文字列の操作に特に関心がある場合の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)
1
Wade
import string

print filter(string.lowercase.__contains__, "lowerUPPER")
print filter("123".__contains__, "a1b2c3")
0
onno

正規表現を使用します。小文字の一致[a-z]の場合。

0
Oli
import string
print "".join([c for c in "Agh#$%#%2341- -!zdrkfd" if c in string.lowercase])
0
Krishnan Thodla