Python:从string中除去数字以外的字符

我如何删除string中除数字以外的所有字符?

在Python 2. *中,最快的方法是.translate方法:

 >>> x='aaa12333bb445bb54b5b52' >>> import string >>> all=string.maketrans('','') >>> nodigs=all.translate(all, string.digits) >>> x.translate(all, nodigs) '1233344554552' >>> 

string.maketrans创build一个转换表(一个长度为256的string),在这种情况下,它与''.join(chr(x) for x in range(256)) (只是更快; ''.join(chr(x) for x in range(256)).translate应用翻译表(这里是不相关的,因为all本质都意味着同一性),并删除第二个参数中出现的字符 – 关键部分。

.translate在Unicodestring(和Python 3中的string) .translate工作方式有很大的不同 – 我希望指定哪些主要版本的Python感兴趣的问题 – 不是很简单,不是很快,但仍然非常有用。

返回2. *,性能差异令人印象深刻…:

 $ python -mtimeit -s'import string; all=string.maketrans("", ""); nodig=all.translate(all, string.digits); x="aaa12333bb445bb54b5b52"' 'x.translate(all, nodig)' 1000000 loops, best of 3: 1.04 usec per loop $ python -mtimeit -s'import re; x="aaa12333bb445bb54b5b52"' 're.sub(r"\D", "", x)' 100000 loops, best of 3: 7.9 usec per loop 

花费7-8倍的速度难花生,所以translate方法值得认识和运用。 其他stream行的非RE方法…:

 $ python -mtimeit -s'x="aaa12333bb445bb54b5b52"' '"".join(i for i in x if i.isdigit())' 100000 loops, best of 3: 11.5 usec per loop 

比RE慢50%,所以.translate方法比它大一个数量级。

在Python 3或Unicode中,您需要传递一个映射(使用.translate ,而不是直接作为键的字符),它将返回None以表示要删除的内容。 这里有一个方便的方式来表示删除“除了”几个字符:

 import string class Del: def __init__(self, keep=string.digits): self.comp = dict((ord(c),c) for c in keep) def __getitem__(self, k): return self.comp.get(k) DD = Del() x='aaa12333bb445bb54b5b52' x.translate(DD) 

也发出'1233344554552' 。 然而,把这个在xx.py中我们有…:

 $ python3.1 -mtimeit -s'import re; x="aaa12333bb445bb54b5b52"' 're.sub(r"\D", "", x)' 100000 loops, best of 3: 8.43 usec per loop $ python3.1 -mtimeit -s'import xx; x="aaa12333bb445bb54b5b52"' 'x.translate(xx.DD)' 10000 loops, best of 3: 24.3 usec per loop 

这表明性能优势消失了,对于这种“删除”任务,并成为一个性能下降。

使用re.sub ,如下所示:

 >>> import re >>> re.sub("\D", "", "aas30dsa20") '3020' 

\D匹配任何非数字字符,所以上面的代码基本上replace了空string的每个非数字字符。

或者你可以使用filter ,就像这样(在Python 2k中):

 >>> filter(lambda x: x.isdigit(), "aas30dsa20") '3020' 

由于在Python 3k中, filter返回一个迭代器而不是一个list ,你可以使用下面的代码:

 >>> ''.join(filter(lambda x: x.isdigit(), "aas30dsa20")) '3020' 
 s=''.join(i for i in s if i.isdigit()) 

另一个发电机变种

你可以使用filter:

 filter(lambda x: x.isdigit(), "dasdasd2313dsa") 

在python3.0你必须join这个(有点丑:( :()

 ''.join(filter(lambda x: x.isdigit(), "dasdasd2313dsa")) 

沿着拜耳的答案:

 ''.join(i for i in s if i.isdigit()) 
 x.translate(None, string.digits) 

将从string中删除所有数字。 要删除字母并保留数字,请执行以下操作:

 x.translate(None, string.letters) 

你可以很容易地使用正则expression式

 >>> import re >>> re.sub("\D","","£70,000") 70000 

操作中提到他要保留小数位。 这可以通过re.sub方法(按照第二和恕我直言最好的答案)通过明确列出字符,以保持例如

 >>> re.sub("[^0123456789\.]","","poo123.4and5fish") '123.45' 

Python 3的快速版本:

 # xx3.py from collections import defaultdict import string _NoneType = type(None) def keeper(keep): table = defaultdict(_NoneType) table.update({ord(c): c for c in keep}) return table digit_keeper = keeper(string.digits) 

这是一个性能比较与正则expression式:

 $ python3.3 -mtimeit -s'import xx3; x="aaa12333bb445bb54b5b52"' 'x.translate(xx3.digit_keeper)' 1000000 loops, best of 3: 1.02 usec per loop $ python3.3 -mtimeit -s'import re; r = re.compile(r"\D"); x="aaa12333bb445bb54b5b52"' 'r.sub("", x)' 100000 loops, best of 3: 3.43 usec per loop 

所以比正则expression式要快三倍多。 它也比上面的class Del更快,因为defaultdict在C中执行所有查找,而不是(慢)Python。 这是在同一个系统上的版本,用于比较。

 $ python3.3 -mtimeit -s'import xx; x="aaa12333bb445bb54b5b52"' 'x.translate(xx.DD)' 100000 loops, best of 3: 13.6 usec per loop 

丑但是作品:

 >>> s 'aaa12333bb445bb54b5b52' >>> a = ''.join(filter(lambda x : x.isdigit(), s)) >>> a '1233344554552' >>> 

使用生成器expression式:

 >>> s = "foo200bar" >>> new_s = "".join(i for i in s if i in "0123456789")