【问题标题】:Remove characters except digits from string using Python?使用Python从字符串中删除除数字以外的字符?
【发布时间】:2010-11-29 20:53:03
【问题描述】:

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

【问题讨论】:

  • @Jan Tojnar:你能举个例子吗?
  • @JG:我有 gtk.Entry(),我想在其中输入乘法浮点数。
  • @JanTojnar 根据答案二使用 re.sub 方法并明确列出要保留的字符,例如re.sub("[^0123456789\.]","","poo123.4and5fish")

标签: python string


【解决方案1】:

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

【讨论】:

  • 这样简单的任务是邪恶的,第二个是我认为最好的,因为'is...'方法对于字符串来说是最快的。
  • 您的过滤器示例仅限于 py2k
  • @f0b0s-iu9-info:你计时了吗?在我的机器(py3k)上,re 比使用 isdigit 的过滤器快两倍,使用 isdigt 的生成器在它们之间
  • @SilentGhost:谢谢,我使用的是 py2k 的 IDLE。现在已经修好了。
  • @asmaier 只需将r 用于原始字符串:re.sub(r"\D+", "", "aas30dsa20")
【解决方案2】:

在 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

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

【讨论】:

  • @sunqiang,是的,绝对——Py3k 使用 Unicode 作为文本字符串类型是有原因的,而不是像 Py2 中的字节字符串——同样的原因 Java 和 C# 一直有相同的“ string 意味着 unicode" meme... 一些开销,也许,但更好地支持除了英语之外的任何东西!-)。
  • x.translate(None, string.digits) 实际上会导致 'aaabbbbbb',这与预期的相反。
  • 与 Tom Dalling 相呼应,您的第一个示例保留了所有不受欢迎的字符 - 与您所说的相反。
  • @RyanB.Lynch 等人,问题出在后来的编辑和另外两个approved said edit 的用户身上,事实上,这是完全错误的。已恢复。
  • 覆盖all builtin...不确定!
【解决方案3】:
s=''.join(i for i in s if i.isdigit())

另一个生成器变体。

【讨论】:

  • 杀了它..+1 如果使用 lamda 会更好
  • 如果您想包含任何自定义字符,例如包含负数或小数 - 请执行以下操作:s = ''.join(i for i in s if i.isdigit() or i in '-./\\')
  • 没有任何进口的绝佳解决方案
【解决方案4】:

你可以使用过滤器:

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

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

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

【讨论】:

  • 仅在 py2k 中,在 py3k 中返回生成器
  • str 转换为 list 以确保它适用于 py2 和 py3:''.join(filter(lambda x: x.isdigit(), list("dasdasd2313dsa")))
【解决方案5】:

按照拜耳的回答:

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

【讨论】:

  • 不,这不适用于负数,因为- 不是数字。
【解决方案6】:

您可以使用正则表达式轻松完成

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

【讨论】:

  • 迄今为止最简单的方法
  • 这与 7 年前提供的 João Silva 的回答有何不同?
【解决方案7】:

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

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

【讨论】:

  • “poo123.4and.5fish”呢?
  • 在我的代码中,我检查输入字符串中的句点数,如果大于 1,则会引发错误。
【解决方案8】:
x.translate(None, string.digits)

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

x.translate(None, string.letters)

【讨论】:

  • 我得到一个 TypeError: translate() 只接受一个参数(给定 2 个)。为什么这个问题在目前的状态下被赞成是非常令人沮丧的。
  • translate 从 python 2 更改为 3。在 python 3 中使用此方法的语法是 x.translate(str.maketrans('', '', string.digits)) 和 x.translate(str .maketrans('', '', string.ascii_letters)) 。这些都没有去除空白。我不会再推荐这种方法了......
【解决方案9】:

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)

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

$ 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

【讨论】:

    【解决方案10】:

    使用生成器表达式:

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

    【讨论】:

    • 改为''.join(n for n in foo if n.isdigit())
    • 稍作修改,"".join([i for i in s if i in "0123456789"]),拜耳的解决方案比使用“isdigit”更快。它的执行时间减少了 15%。在此页面上提供的所有解决方案中,最快的是 @rescdsk 的。但是,当不是循环时,最好还是坚持最快的“单线”方案。
    【解决方案11】:

    试试:

    import re
    
    string = '1abcd2XYZ3'
    string_without_letters = re.sub(r'[a-z]', '', string.lower())
    

    这应该给出:

    123
    

    【讨论】:

    • so [a-z] 表示所有小写字母或大写我们必须[A-Z]
    • [a-z] 适用于小写和大写 :)
    • 是的,因为我刚刚注意到string.lower() 是你最好的朋友。
    【解决方案12】:

    丑陋但有效:

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

    【讨论】:

    • @SilentGhost 这是我的误解。有没有更正谢谢:)
    • 其实用这个方法,我觉得你不需要使用“join”。 filter(lambda x: x.isdigit(), s) 对我来说效果很好。 ...哦,那是因为我使用的是 Python 2.7。
    【解决方案13】:

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

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

    【讨论】:

    • 这与 f0b0s 的答案有何不同?如果您有更多信息要提供,则应该编辑该答案
    【解决方案14】:
    $ 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 微秒

    我观察到 join 比 sub 快。

    【讨论】:

    • 为什么要把这两种方法重复两次?您能否描述一下您的答案与接受的答案有何不同?
    • 两者的输出相同。但是,我只是想表明 join 在结果中的 sub 方法更快。
    • 他们没有,你的代码正好相反。而且你有四种测量方法,但只有两种方法。
    【解决方案15】:

    不是单行但非常简单:

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

    【讨论】:

      【解决方案16】:

      我用过这个。 '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

      【讨论】:

        【解决方案17】:
        my_string="sdfsdfsdfsfsdf353dsg345435sdfs525436654.dgg(" 
        my_string=''.join((ch if ch in '0123456789' else '') for ch in my_string)
        print(output:+my_string)
        

        输出:353345435525436654

        【讨论】:

        • 添加这个,以及小数点,if ch in '0123456789.' else '',这样.也会被添加。
        猜你喜欢
        • 2023-01-04
        • 1970-01-01
        • 2017-09-01
        • 2023-02-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-29
        相关资源
        最近更新 更多