代码之家  ›  专栏  ›  技术社区  ›  Jan Tojnar

python:从字符串中删除除数字以外的字符

  •  109
  • Jan Tojnar  · 技术社区  · 15 年前

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

    13 回复  |  直到 6 年前
        1
  •  102
  •   rescdsk    10 年前

    在Python2.*中,最快的方法是 .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)) (做得更快;-)。 翻译 应用翻译表(此处与此无关,因为 all 本质上是指标识),并删除第二个参数(关键部分)中的字符。

    翻译 在Unicode字符串(以及Python3中的字符串——i)上的工作方式非常不同 希望问题指定哪个主要版本的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 方法是非常值得了解和使用的。另一种流行的非重复方法…:

    $ 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%,所以 翻译 接近比它大一个数量级。

    在python 3或unicode中,您需要传递 翻译 返回的一种映射(用序数而不是直接用字符作为键) 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
    

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

        2
  •  157
  •   João Silva    15 年前

    使用 re.sub ,像这样:

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

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

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

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

    在python 3k中, 滤波器 返回迭代器而不是 list 你可以用下面的方法来代替:

    >>> ''.join(filter(lambda x: x.isdigit(), "aas30dsa20"))
    '3020'
    
        3
  •  56
  •   f0b0s    15 年前
    s=''.join(i for i in s if i.isdigit())
    

    另一种发电机变体。

        4
  •  16
  •   freiksenet    15 年前

    可以使用过滤器:

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

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

    ''.join(filter(lambda x: x.isdigit(), "dasdasd2313dsa"))
    
        5
  •  10
  •   SilentGhost    15 年前

    按照拜耳的回答:

    ''.join(i for i in s if i.isdigit())
    
        6
  •  9
  •   Aminah Nuraini    8 年前

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

    >>> import re
    >>> re.sub("\D","","£70,000")
    70000
    
        7
  •  7
  •   Gilles 'SO- stop being evil'    11 年前
    x.translate(None, string.digits)
    

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

    x.translate(None, string.letters)
    
        8
  •  5
  •   Roger Heathcote    12 年前

    操作人员在评论中提到他想保留小数点。这可以通过使用re.sub方法(根据第二个和imho最佳答案)来完成,方法是显式地列出要保留的字符,例如

    >>> re.sub("[^0123456789\.]","","poo123.4and5fish")
    '123.45'
    
        9
  •  4
  •   rescdsk    10 年前

    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
    

    所以对我来说,它比regex快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
  •  2
  •   Gant    15 年前

    丑陋但有效:

    >>> s
    'aaa12333bb445bb54b5b52'
    >>> a = ''.join(filter(lambda x : x.isdigit(), s))
    >>> a
    '1233344554552'
    >>>
    
        11
  •  1
  •   bayer    15 年前

    使用生成器表达式:

    >>> s = "foo200bar"
    >>> new_s = "".join(i for i in s if i in "0123456789")
    
        12
  •  0
  •   Josh    7 年前

    不是一行,而是非常简单:

    buffer = ""
    some_str = "aas30dsa20"
    
    for char in some_str:
        if not char.isdigit():
            buffer += char
    
    print( buffer )
    
        13
  •  0
  •   AnilReddy    6 年前
    $ python -mtimeit -s'import re;  x="aaa12333bb445bb54b5b52"' 're.sub(r"\D", "", x)'
    

    100000个循环,最好是3个:每个循环2.48 usec

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

    100000个循环,最好是3个:每个循环2.02 usec

    $python-mtimeit-s'import re;x=“aaa1233bb445bb54b5b52”''re.sub(r“\d”,“”,x)'
    

    100000个循环,最好是3个:每个循环2.37 usec

    $python-mtimeit-s'import re;x=“aaa1233bab445b54b5b2”''。连接(re.findall(“[a-z]+”,x))'
    

    100000个循环,最好是3个:每个循环1.97 usec

    我注意到,连接比sub快。