Python:从字符串中删除除数字之外的字符

Jan*_*nar 124 python string

如何从字符串中删除除数字之外的所有字符?

Joã*_*lva 175

使用re.sub,像这样:

>>> import re
>>> re.sub("\D", "", "aas30dsa20")
'3020'
Run Code Online (Sandbox Code Playgroud)

\D 匹配任何非数字字符,因此,上面的代码实际上替换了空字符串的每个非数字字符.

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

>>> filter(lambda x: x.isdigit(), "aas30dsa20")
'3020'
Run Code Online (Sandbox Code Playgroud)

因为在Python 3k中,filter返回迭代器而不是a list,您可以使用以下代码:

>>> ''.join(filter(lambda x: x.isdigit(), "aas30dsa20"))
'3020'
Run Code Online (Sandbox Code Playgroud)

  • @asmaier 只需使用 `r` 作为原始字符串: `re.sub(r"\D+", "", "aas30dsa20")` (4认同)
  • 对于 Python 3.6,它应该是 `re.sub("\\D", "", "aas30dsa20")` 。否则会收到“DeprecationWarning:无效转义序列 \D”。 (3认同)
  • @ f0b0s-iu9-info:您是否定时?在我的机器(py3k)上,re的速度是使用`isdigit`的过滤器的两倍,使用`isdigt`的生成器在它们之间的一半 (2认同)

Ale*_*lli 108

在Python 2.*中,到目前为止最快的方法是.translate方法:

>>> x='aaa12333bb445bb54b5b52'
>>> import string
>>> all=string.maketrans('','')
>>> nodigs=all.translate(all, string.digits)
>>> x.translate(all, nodigs)
'1233344554552'
>>> 
Run Code Online (Sandbox Code Playgroud)

string.maketrans制作一个转换表(长度为256的字符串),在这种情况下是相同的''.join(chr(x) for x in range(256))(只是更快;-)..translate应用转换表(这里不相关,因为all本质上意味着身份)并删除第二个参数中存在的字符 - 关键部分.

.translate在Unicode字符串(和Python 3中的字符串 - 我确实希望问题指出哪些主要版本的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
Run Code Online (Sandbox Code Playgroud)

加速7到8倍的东西几乎不是花生,所以这种translate方法非常值得了解和使用.另一种流行的非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
Run Code Online (Sandbox Code Playgroud)

比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)
Run Code Online (Sandbox Code Playgroud)

也发出'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
Run Code Online (Sandbox Code Playgroud)

...显示性能优势消失,对于这种"删除"任务,并成为性能下降.

  • `x.translate(None,string.digits)`实际上会产生''aaabbbbbb',这与预期相反. (29认同)
  • 回应Tom Dalling的评论,你的第一个例子保留了所有不良角色 - 与你说的相反. (4认同)
  • @ RyanB.Lynch等人,故障发生在后来的编辑和另外两位用户[批准上述编辑](http://stackoverflow.com/review/suggested-edits/343120),实际上这是完全错误的.还原. (3认同)
  • 覆盖 `all` 内置......不确定! (2认同)

f0b*_*b0s 58

s=''.join(i for i in s if i.isdigit())
Run Code Online (Sandbox Code Playgroud)

另一种发电机型号

  • 如果您想包含任何自定义字符,例如包含负数或小数 - 请执行以下操作: `s = ''.join(i for i in s if i.isdigit() or i in '-./\\')` (2认同)

fre*_*net 16

你可以使用过滤器:

filter(lambda x: x.isdigit(), "dasdasd2313dsa")
Run Code Online (Sandbox Code Playgroud)

在python3.0你必须加入这个(有点难看:()

''.join(filter(lambda x: x.isdigit(), "dasdasd2313dsa"))
Run Code Online (Sandbox Code Playgroud)


Sil*_*ost 11

沿着拜耳的回答:

''.join(i for i in s if i.isdigit())
Run Code Online (Sandbox Code Playgroud)


Ami*_*ini 11

您可以使用Regex轻松完成

>>> import re
>>> re.sub("\D","","£70,000")
70000
Run Code Online (Sandbox Code Playgroud)

  • 这与7年前提供的若昂·席尔瓦(JoãoSilva)的答案有何不同? (2认同)

小智 7

x.translate(None, string.digits)
Run Code Online (Sandbox Code Playgroud)

将删除字符串中的所有数字.要删除字母并保留数字,请执行以下操作:

x.translate(None, string.letters)
Run Code Online (Sandbox Code Playgroud)

  • 我得到一个`TypeError`:translate()只接受一个参数(给定2个).为什么这个问题在目前的状态下被投票是非常令人沮丧的. (3认同)

Joã*_*oão 6

尝试:

import re

string = '1abcd2XYZ3'
string_without_letters = re.sub(r'[a-z]', '', string.lower())
Run Code Online (Sandbox Code Playgroud)

这应该给出:

123
Run Code Online (Sandbox Code Playgroud)


bay*_*yer 5

使用生成器表达式:

>>> s = "foo200bar"
>>> new_s = "".join(i for i in s if i in "0123456789")
Run Code Online (Sandbox Code Playgroud)


tec*_*oke 5

评论中提到他希望保留小数位.这可以通过re.sub方法(根据第二个和恕我直言最佳答案)通过明确列出要保持的字符来完成

>>> re.sub("[^0123456789\.]","","poo123.4and5fish")
'123.45'
Run Code Online (Sandbox Code Playgroud)


res*_*dsk 5

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)
Run Code Online (Sandbox Code Playgroud)

这是与正则表达式的性能比较:

$ 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
Run Code Online (Sandbox Code Playgroud)

所以对我来说,它比正则表达式快 3 倍多一点。它也比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
Run Code Online (Sandbox Code Playgroud)