在Python中去除字符串中的非字母数字字符

466 投票
16 回答
550786 浏览
提问于 2025-04-15 13:36

如何用Python去掉字符串中所有非字母数字的字符,最好的方法是什么?

在这个问题的PHP版本中提出的解决方案可能经过一些小调整后也能用,但我觉得它们看起来不太“符合Python风格”。

顺便说一下,我不仅仅想去掉句号和逗号(还有其他标点符号),还想去掉引号、括号等等。

16 个回答

80

使用 str.translate() 方法。

假设你会经常这样做:

  1. 首先,创建一个包含你想删除的所有字符的字符串:

    delchars = ''.join(c for c in map(chr, range(256)) if not c.isalnum())
    
  2. 每当你想压缩一个字符串时:

    scrunched = s.translate(None, delchars)
    

设置的成本可能和 re.compile 相比还不错;而后续的成本要低得多:

C:\junk>\python26\python -mtimeit -s"import string;d=''.join(c for c in map(chr,range(256)) if not c.isalnum());s=string.printable" "s.translate(None,d)"
100000 loops, best of 3: 2.04 usec per loop

C:\junk>\python26\python -mtimeit -s"import re,string;s=string.printable;r=re.compile(r'[\W_]+')" "r.sub('',s)"
100000 loops, best of 3: 7.34 usec per loop

注意:使用 string.printable 作为基准数据会让模式 '[\W_]+' 有不公平的优势;因为所有的非字母数字字符都在一块……在典型的数据中,可能需要做的不止一次替换:

C:\junk>\python26\python -c "import string; s = string.printable; print len(s),repr(s)"
100 '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c'

如果你让 re.sub 多做一点工作,会发生这样的情况:

C:\junk>\python26\python -mtimeit -s"d=''.join(c for c in map(chr,range(256)) if not c.isalnum());s='foo-'*25" "s.translate(None,d)"
1000000 loops, best of 3: 1.97 usec per loop

C:\junk>\python26\python -mtimeit -s"import re;s='foo-'*25;r=re.compile(r'[\W_]+')" "r.sub('',s)"
10000 loops, best of 3: 26.4 usec per loop
379

正则表达式来帮忙:

import re
re.sub(r'\W+', '', your_string)

在Python中,'\W'的意思是[^a-zA-Z0-9_],这表示排除了所有的数字字母_符号。

455

我出于好奇,测试了一些函数的运行时间。在这些测试中,我从字符串 string.printable 中去掉了非字母数字的字符(这个字符串是内置的 string 模块的一部分)。我发现使用编译后的 '[\W_]+'pattern.sub('', str) 的速度是最快的。

$ python -m timeit -s \
     "import string" \
     "''.join(ch for ch in string.printable if ch.isalnum())" 
10000 loops, best of 3: 57.6 usec per loop

$ python -m timeit -s \
    "import string" \
    "filter(str.isalnum, string.printable)"                 
10000 loops, best of 3: 37.9 usec per loop

$ python -m timeit -s \
    "import re, string" \
    "re.sub('[\W_]', '', string.printable)"
10000 loops, best of 3: 27.5 usec per loop

$ python -m timeit -s \
    "import re, string" \
    "re.sub('[\W_]+', '', string.printable)"                
100000 loops, best of 3: 15 usec per loop

$ python -m timeit -s \
    "import re, string; pattern = re.compile('[\W_]+')" \
    "pattern.sub('', string.printable)" 
100000 loops, best of 3: 11.2 usec per loop

撰写回答