如何过滤字符串,以便只返回列表中的字符?

时间:2009-05-15 19:48:02

标签: python filter whitelist

想象一个字符串,比如'Agh#$%#%2341- - !zdrkfd',我只希望对它进行一些操作,只返回小写字母(例如),在这种情况下会带上'ghzdrkfd'。

你是如何用Python做到的?显而易见的方法是创建一个字符列表,'a'到'z',然后迭代我的字符串中的字符,并逐个字符地构建一个新字符串。这看起来很原始。

我想知道正则表达式是否合适。替换不需要的字符似乎有问题,我倾向于将白名单优先于黑名单。 .match函数似乎不合适。我查看了Python网站上的相应页面,但没有找到适合的方法。

如果正则表达式不合适并且正确的方法是循环,是否有一个简单的函数将字符串“爆炸”到列表中?或者我只是在那里打另一个循环?

10 个答案:

答案 0 :(得分:32)

如果您正在寻找效率。使用translate功能是最快的。

它可用于快速替换字符和/或删除它们。

import string
delete_table  = string.maketrans(
    string.ascii_lowercase, ' ' * len(string.ascii_lowercase)
)
table = string.maketrans('', '')

"Agh#$%#%2341- -!zdrkfd".translate(table, delete_table)

在python 2.6:中,您不再需要第二个表

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

答案 1 :(得分:18)

s = 'Agh#$%#%2341- -!zdrkfd'  
print ''.join(c for c in s if c.islower())

String对象是可迭代的;没有必要将字符串“爆炸”成列表。你可以在列表理解中放入你想要的任何条件,它会相应地过滤字符。

您也可以使用正则表达式实现此功能,但这只会隐藏循环。正则表达式库仍然必须遍历字符串的字符才能过滤它们。

答案 2 :(得分:5)

使用正则表达式很容易,特别是对于这种情况:

>>> 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'

答案 3 :(得分:4)

s = 'ASDjifjASFJ7364'
s_lowercase = ''.join(filter(lambda c: c.islower(), s))
print s_lowercase #print 'jifj'

答案 4 :(得分:4)

>>> s = 'Agh#$%#%2341- -!zdrkfd'
>>> ''.join(i for i in s if  i in 'qwertyuiopasdfghjklzxcvbnm')
'ghzdrkfd'

答案 5 :(得分:2)

采用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调用将从输入字符串中删除那些并产生所需的结果。

答案 6 :(得分: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(function,iterable)

     

从iterable的那些元素构造一个列表,该函数返回true。 iterable可以是序列,支持迭代的容器,也可以是迭代器。如果iterable是字符串或元组,则结果也具有该类型;否则它总是一个列表。如果function为None,则假定为identity函数,即删除所有可迭代的false元素。

这是使用filter()的一种方式:

filtered_list = filter(lambda c: c.islower(), s)

答案 7 :(得分:0)

我会使用正则表达式。对于小写匹配[a-z]。

答案 8 :(得分:0)

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

答案 9 :(得分:0)

import string

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