【问题标题】:Strip all non-numeric characters (except for ".") from a string in Python从 Python 中的字符串中去除所有非数字字符(“.”除外)
【发布时间】:2009-06-03 23:12:00
【问题描述】:

我有一个很好的工作代码片段,但我想知道是否有人对如何做到这一点有更好的建议:

val = ''.join([c for c in val if c in '1234567890.'])

你会怎么做?

【问题讨论】:

  • 因为我被网络搜索扫到了这里,所以我只想补充一点,如果可能出现负数,人们一定不要忘记为自己的代码添加-
  • 哇,这对于简单的任务来说非常整洁

标签: python


【解决方案1】:

您可以使用正则表达式(使用re 模块)来完成同样的事情。下面的示例匹配 [^\d.] 的运行(任何不是十进制数字或句点的字符)并将它们替换为空字符串。请注意,如果使用UNICODE 标志编译模式,则生成的字符串仍可能包含non-ASCII numbers。另外,去掉“非数字”字符后的结果不一定是有效数字。

>>> import re
>>> non_decimal = re.compile(r'[^\d.]+')
>>> non_decimal.sub('', '12.34fe4e')
'12.344'

【讨论】:

  • reg-ex 会更快!
  • +1 用于包含量词。请注意,在这种情况下您不需要编译模式; Python 缓存最近使用的模式。相反,只需使用re.sub(r'[^\d.]+', '', '12.34fe4e')
  • Python 确实缓存了最近使用的模式(最后 100 个,如果有记忆的话),但我喜欢这里的编译,只是因为你可以通过一个合理的名称来引用模式,而不是每次都在心理上解码正则表达式阅读代码的时间。
  • 355.fhfg55.ty55g 的代码中断
  • @PranavWaila 你期望结果是什么?
【解决方案2】:

另一种“pythonic”方法

filter( lambda x: x in '0123456789.', s )

但正则表达式更快。

【讨论】:

    【解决方案3】:

    这里有一些示例代码:

    $ cat a.py
    a = '27893jkasnf8u2qrtq2ntkjh8934yt8.298222rwagasjkijw'
    for i in xrange(1000000):
        ''.join([c for c in a if c in '1234567890.'])
    

    $ cat b.py
    import re
    
    non_decimal = re.compile(r'[^\d.]+')
    
    a = '27893jkasnf8u2qrtq2ntkjh8934yt8.298222rwagasjkijw'
    for i in xrange(1000000):
        non_decimal.sub('', a)
    

    $ cat c.py
    a = '27893jkasnf8u2qrtq2ntkjh8934yt8.298222rwagasjkijw'
    for i in xrange(1000000):
        ''.join([c for c in a if c.isdigit() or c == '.'])
    

    $ cat d.py
    a = '27893jkasnf8u2qrtq2ntkjh8934yt8.298222rwagasjkijw'
    for i in xrange(1000000):
        b = []
        for c in a:
            if c.isdigit() or c == '.': continue
            b.append(c)
    
        ''.join(b)
    

    以及计时结果:


    $ time python a.py
    real    0m24.735s
    user    0m21.049s
    sys     0m0.456s
    
    $ time python b.py
    real    0m10.775s
    user    0m9.817s
    sys     0m0.236s
    
    $ time python c.py
    real    0m38.255s
    user    0m32.718s
    sys     0m0.724s
    
    $ time python d.py
    real    0m46.040s
    user    0m41.515s
    sys     0m0.832s
    

    到目前为止,看起来正则表达式是赢家。

    就我个人而言,我发现正则表达式与列表理解一样具有可读性。如果你只做了几次,那么你可能会在编译正则表达式时受到更大的打击。做适合你的代码和编码风格的事情。

    【讨论】:

    • 您可以使用 timeit 模块更轻松(更准确)地执行这些微基准测试。例如: $ python -m timeit -s "import re; non_decimal = re.compile(r'[^\d.]+'); a = '27893jkasnf8u2qrtq2ntkjh8934yt8.298222rwagasjkijw'" "non_decimal.sub('', a) "
    • 这让我得到 10.7 我们。 1e6 循环的 10.775s 足够接近 10.7 us。 :)
    • +1 用于考虑上下文“用你的代码和编码风格做事”
    【解决方案4】:

    一个简单的解决方案是使用正则表达式

    import re 
    re.sub("[^0-9^.]", "", data)
    

    【讨论】:

      【解决方案5】:
      import string
      filter(lambda c: c in string.digits + '.', s)
      

      【讨论】:

        【解决方案6】:

        如果字符集更大,使用如下集可能会更快。事实上,这比 a.py 慢了一点。

        dec = set('1234567890.')
        
        a = '27893jkasnf8u2qrtq2ntkjh8934yt8.298222rwagasjkijw'
        for i in xrange(1000000):
            ''.join(ch for ch in a if ch in dec)

        至少在我的系统上,您可以通过在 a.py 中使用生成器表达式而不是列表推导来节省一点点时间(如果您的字符串足够长,还可以节省内存):

        a = '27893jkasnf8u2qrtq2ntkjh8934yt8.298222rwagasjkijw'
        for i in xrange(1000000):
            ''.join(c for c in a if c in '1234567890.')

        哦,这是迄今为止我在这个测试字符串上找到的最快方法(比正则表达式快得多),如果你这样做很多次并且愿意忍受构建几个字符的开销表格。

        chrs = ''.join(chr(i) for i in xrange(256))
        deletable = ''.join(ch for ch in chrs if ch not in '1234567890.')
        
        a = '27893jkasnf8u2qrtq2ntkjh8934yt8.298222rwagasjkijw'
        for i in xrange(1000000):
            a.translate(chrs, deletable)

        在我的系统上,运行时间约为 1.0 秒,而正则表达式 b.py 运行时间约为 4.3 秒。

        【讨论】:

          猜你喜欢
          • 2010-12-24
          • 2018-10-21
          • 2010-11-17
          • 2011-04-28
          • 2011-09-13
          相关资源
          最近更新 更多