使用Python从字符串中删除数字以外的字符?


137

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


@Jan Tojnar:能举个例子吗?
若昂·席尔瓦

@JG:我有gtk.Entry(),我想输入倍数浮点数。
2009年

1
@JanTojnar按照答案2使用re.sub方法,并明确列出要保留的字符,例如re.sub(“ [^ 0123456789 \。]”,“”,“ poo123.4and5fish”)
Roger Heathcote

Answers:


112

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

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

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

将事情加速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

比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

...表明性能优势对于这种“删除”任务消失了,而变成了性能下降。


1
@sunqiang,是的,绝对是的-有一个原因Py3k已将Unicode用作文本字符串类型,而不是像Py2中的字节字符串一样-Java和C#始终具有相同的“字符串表示unicode”模因是同样的原因...也许有些开销,但是除了英语以外,几乎可以更好地支持任何其他内容!-)。
亚历克斯·马丁里

29
x.translate(None, string.digits)实际上会导致'aaabbbbbb',这与预期的相反。
汤姆·达林

4
与汤姆·达林(Tom Dalling)的评论相呼应,第一个示例保留了所有不受欢迎的字符-与您所说的相反。
克里斯·约翰逊

3
@ RyanB.Lynch等人的过错是由后来的编辑器和其他两个批准所述edit的用户造成的,实际上,这是完全错误的。已还原。
尼克T

1
覆盖all内置的...对此不确定!
安迪·海登

197

使用re.sub,如下所示:

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

\D 匹配任何非数字字符,因此,上面的代码实质上是将每个非数字字符替换为空字符串。

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

>>> filter(str.isdigit, 'aas30dsa20')
'3020'

由于在Python 3中,filter返回的是迭代器而不是list,因此您可以使用以下代码:

>>> ''.join(filter(str.isdigit, 'aas30dsa20'))
'3020'

在这样简单的任务中re是邪恶的,第二个是我认为最好的,因为'is ...'方法对于字符串来说是最快的。
f0b0s

您的过滤器例如仅限于py2k
SilentGhost

2
@ f0b0s-iu9-info:您是否定时?在我的机器(py3k)上,re的速度是使用的过滤器的两倍isdigit,其中的发电机isdigt
SilentGhost

@SilentGhost:谢谢,我使用的是py2k中的IDLE。现在已修复。
若昂·席尔瓦

1
@asmaier只需将其r用于原始字符串即可:re.sub(r"\D+", "", "aas30dsa20")
Mitch McMabers

64
s=''.join(i for i in s if i.isdigit())

另一个发电机变体。


杀死了它.. + 1如果使用lamda,那就更好了
Barath Ravikumar

17

您可以使用过滤器:

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

在python3.0上,您必须加入这个(有点丑陋的:()

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

只有在py2k,在py3k它返回一个发电机
SilentGhost

转换strlist以确保它可以同时在py2和py3上使用:''.join(filter(lambda x: x.isdigit(), list("dasdasd2313dsa")))
Luiz C.

13

按照拜耳的回答:

''.join(i for i in s if i.isdigit())

不,这对于负数不起作用,因为-它不是数字。
奥利


7
x.translate(None, string.digits)

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

x.translate(None, string.letters)

3
我得到一个TypeError:translate()正好接受一个参数(给定2个)。为什么在当前状态下对此问题提出质疑,这是非常令人沮丧的。
Bobort '16

从python 2转换为3。在python 3中使用此方法的语法为x.translate(str.maketrans('',``,string.digits))和x.translate(str.maketrans('','' ,string.ascii_letters))。这些都不带空格。我真的不会再推荐这种方法了……
ZaxR

5

这位操作员在评论中提到他想保留小数位。可以通过re.sub方法(按照第二个方法和恕我直言的最佳答案)来完成,方法是明确列出要保留的字符,例如

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

那“ poo123.4and.5fish”呢?
Jan Tojnar 2013年

在我的代码检查期间的输入字符串的数量,如果这是引发错误大于1
罗杰·希思科特

4

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)

这是与regex的性能比较:

$ 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

对我来说,它比正则表达式快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

3

使用生成器表达式:

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

而是这样做''.join(n for n in foo if n.isdigit())
shxfee 2015年

2

丑陋但可行:

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

你为什么list(s)呢?
SilentGhost

@SilentGhost这是我的误会。纠正了吗:)
Gant

实际上,通过这种方法,我认为您不需要使用“ join”。 filter(lambda x: x.isdigit(), s)对我来说很好。...哦,这是因为我正在使用Python 2.7。
Bobort's

1
$ python -mtimeit -s'import re;  x="aaa12333bb445bb54b5b52"' 're.sub(r"\D", "", x)'

100000次循环,每循环3:2.48微秒最佳

$ python -mtimeit -s'import re; x="aaa12333bab445bb54b5b52"' '"".join(re.findall("[a-z]+",x))'

100000次循环,最好为3:每个循环2.02微秒

$ python -mtimeit -s'import re;  x="aaa12333bb445bb54b5b52"' 're.sub(r"\D", "", x)'

100000次循环,每循环3:2.37最佳

$ python -mtimeit -s'import re; x="aaa12333bab445bb54b5b52"' '"".join(re.findall("[a-z]+",x))'

100000次循环,每循环3:1.97最佳

我已经观察到联接比sub快。


为什么要重复两次这两种方法?您能否描述您的答案与已接受的答案有何不同?
Jan Tojnar

两者结果相同。但是,我只是想表明join可以更快地显示结果中的sub方法。
AnilReddy

他们没有,您的代码却相反。而且您有四个测量值,但是只有两种方法。
Jan Tojnar '18

1

您可以阅读每个字符。如果是数字,则将其包括在答案中。该str.isdigit() 方法是一种知道字符是否为数字的方法。

your_input = '12kjkh2nnk34l34'
your_output = ''.join(c for c in your_input if c.isdigit())
print(your_output) # '1223434'

这与f0b0s的答案有何不同?如果您需要更多信息,则应该编辑该答案
chevybow

0

不是一个班轮,但非常简单:

buffer = ""
some_str = "aas30dsa20"

for char in some_str:
    if not char.isdigit():
        buffer += char

print( buffer )

0

我用这个 'letters'应该包含您要删除的所有字母:

Output = Input.translate({ord(i): None for i in 'letters'}))

例:

Input = "I would like 20 dollars for that suit" Output = Input.translate({ord(i): None for i in 'abcdefghijklmnopqrstuvwxzy'})) print(Output)

输出: 20

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.