从Python中的字符串中删除除字母数字字符之外的所有内容

Mar*_*ent 295 python string

使用Python从字符串中删除所有非字母数字字符的最佳方法是什么?

这个问题PHP变体中提出的解决方案可能会进行一些微小的调整,但对我来说似乎不太"pythonic".

为了记录,我不仅要删除句点和逗号(以及其他标点符号),还要删除引号,括号等.

Ott*_*ger 305

我只是出于好奇而计算了一些功能.在这些测试中,我将从字符串中删除非字母数字字符string.printable(内置string模块的一部分).

$ 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
Run Code Online (Sandbox Code Playgroud)

  • 对于记录:使用`re.compile('[\ W _] +',re.UNICODE)`使其unicode安全. (41认同)
  • @maudulus使用[regex](https://pypi.python.org/pypi/regex)模块:`re.compile('[\ W _] - []] +')`` - 减去从第一集开始.见[这个答案](http://stackoverflow.com/a/39024781/420867). (8认同)
  • 非常有趣的结果:我原以为正则表达式会更慢。有趣的是,我尝试了另一个选项(`valid_characters = string.ascii_letters + string.digits` 后跟`join(ch for ch in string.printable if ch in valid_characters)`,它比`isalnum( )` 选项。不过仍然比正则表达式慢得多。 (3认同)
  • 而不是str.isalnum,使用unicode.isalnum (3认同)
  • 不删除空格就行:re.sub('[\ W _] +','',sentence,flags = re.UNICODE) (3认同)
  • 如何在不删除空白的情况下做到这一点? (2认同)

Ant*_*sma 238

拯救的正则表达式:

import re
re.sub(r'\W+', '', your_string)
Run Code Online (Sandbox Code Playgroud)

通过Python定义'\W== [^a-zA-Z0-9_],排除所有numbers,letters_

  • 在这种情况下它可能不相关,但`\ W`也会保留下划线. (18认同)
  • 关注@Blixt提示,如果你只想要字母和数字,你可以做re.sub(r'[^ a-zA-Z0-9]','',your_string) (10认同)
  • @Mark:我想它会加速替换,因为替换将一次性去除块中的所有非单词字符,而不是逐个删除它们. (6认同)
  • 加号在正则表达式中起什么作用?(我知道它意味着什么,只是好奇为什么它需要re.sub.) (2认同)
  • 是的,我在不久之前调整了一些性能关键代码.如果有大量的字符替换加速是巨大的. (2认同)
  • @Nigini 这样做你会扔掉一大堆有效的信件。 (2认同)
  • 非英文字母。或者如果您愿意,也可以使用非 ASCII 字符。 (2认同)

Joh*_*hin 67

使用str.translate()方法.

假设你经常这样做:

(1)一次,创建一个包含您要删除的所有字符的字符串:

delchars = ''.join(c for c in map(chr, range(256)) if not c.isalnum())
Run Code Online (Sandbox Code Playgroud)

(2)每当你想要一个字符串:

scrunched = s.translate(None, delchars)
Run Code Online (Sandbox Code Playgroud)

设置成本可能与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
Run Code Online (Sandbox Code Playgroud)

注意:使用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'
Run Code Online (Sandbox Code Playgroud)

如果你给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
Run Code Online (Sandbox Code Playgroud)

  • 这绝对是最pythonic的解决方案. (3认同)
  • 注意:这在Python 3中不再有效. (3认同)
  • 这几乎说服了我,但我建议使用 `string.punctuation` 而不是 `''.join(c for c in map(chr, range(256)) if not c.isalnum())` (2认同)
  • 请注意,这适用于 `str` 对象,但不适用于 `unicode` 对象。 (2认同)

ars*_*ars 37

你可以尝试:

print ''.join(ch for ch in some_string if ch.isalnum())
Run Code Online (Sandbox Code Playgroud)


Dis*_*sie 14

>>> import re
>>> string = "Kl13@£$%[};'\""
>>> pattern = re.compile('\W')
>>> string = re.sub(pattern, '', string)
>>> print string
Kl13
Run Code Online (Sandbox Code Playgroud)


DrA*_*rAl 12

怎么样:

def ExtractAlphanumeric(InputString):
    from string import ascii_letters, digits
    return "".join([ch for ch in InputString if ch in (ascii_letters + digits)])
Run Code Online (Sandbox Code Playgroud)

这通过使用列表推导来生成字符列表(InputString如果它们存在于组合字符串ascii_lettersdigits字符串中).然后它将列表连接成一个字符串.


Nic*_*mer 10

我用perfplot (我的一个项目)检查了结果,发现对于短字符串,

"".join(filter(str.isalnum, s))
Run Code Online (Sandbox Code Playgroud)

是最快的。对于长字符串(200+ 个字符)

re.sub("[\W_]", "", s)
Run Code Online (Sandbox Code Playgroud)

是最快的。

在此输入图像描述

重现情节的代码:

import perfplot
import random
import re
import string

pattern = re.compile("[\W_]+")


def setup(n):
    return "".join(random.choices(string.ascii_letters + string.digits, k=n))


def string_alphanum(s):
    return "".join(ch for ch in s if ch.isalnum())


def filter_str(s):
    return "".join(filter(str.isalnum, s))


def re_sub1(s):
    return re.sub("[\W_]", "", s)


def re_sub2(s):
    return re.sub("[\W_]+", "", s)


def re_sub3(s):
    return pattern.sub("", s)


b = perfplot.bench(
    setup=setup,
    kernels=[string_alphanum, filter_str, re_sub1, re_sub2, re_sub3],
    n_range=[2**k for k in range(10)],
)
b.save("out.png")
b.show()
Run Code Online (Sandbox Code Playgroud)


小智 7

sent = "".join(e for e in sent if e.isalpha())
Run Code Online (Sandbox Code Playgroud)


Sol*_*cko 7

使用随机 ASCII 打印字符串进行计时:

from inspect import getsource
from random import sample
import re
from string import printable
from timeit import timeit

pattern_single = re.compile(r'[\W]')
pattern_repeat = re.compile(r'[\W]+')
translation_tb = str.maketrans('', '', ''.join(c for c in map(chr, range(256)) if not c.isalnum()))


def generate_test_string(length):
    return ''.join(sample(printable, length))


def main():
    for i in range(0, 60, 10):
        for test in [
            lambda: ''.join(c for c in generate_test_string(i) if c.isalnum()),
            lambda: ''.join(filter(str.isalnum, generate_test_string(i))),
            lambda: re.sub(r'[\W]', '', generate_test_string(i)),
            lambda: re.sub(r'[\W]+', '', generate_test_string(i)),
            lambda: pattern_single.sub('', generate_test_string(i)),
            lambda: pattern_repeat.sub('', generate_test_string(i)),
            lambda: generate_test_string(i).translate(translation_tb),

        ]:
            print(timeit(test), i, getsource(test).lstrip('            lambda: ').rstrip(',\n'), sep='\t')


if __name__ == '__main__':
    main()
Run Code Online (Sandbox Code Playgroud)

结果(Python 3.7):

       Time       Length                           Code                           
6.3716264850008880  00  ''.join(c for c in generate_test_string(i) if c.isalnum())
5.7285426190064750  00  ''.join(filter(str.isalnum, generate_test_string(i)))
8.1875841680011940  00  re.sub(r'[\W]', '', generate_test_string(i))
8.0002205439959650  00  re.sub(r'[\W]+', '', generate_test_string(i))
5.5290945199958510  00  pattern_single.sub('', generate_test_string(i))
5.4417179649972240  00  pattern_repeat.sub('', generate_test_string(i))
4.6772285089973590  00  generate_test_string(i).translate(translation_tb)
23.574712151996210  10  ''.join(c for c in generate_test_string(i) if c.isalnum())
22.829975890002970  10  ''.join(filter(str.isalnum, generate_test_string(i)))
27.210196289997840  10  re.sub(r'[\W]', '', generate_test_string(i))
27.203713296003116  10  re.sub(r'[\W]+', '', generate_test_string(i))
24.008979928999906  10  pattern_single.sub('', generate_test_string(i))
23.945240008994006  10  pattern_repeat.sub('', generate_test_string(i))
21.830899796994345  10  generate_test_string(i).translate(translation_tb)
38.731336012999236  20  ''.join(c for c in generate_test_string(i) if c.isalnum())
37.942474347000825  20  ''.join(filter(str.isalnum, generate_test_string(i)))
42.169366310001350  20  re.sub(r'[\W]', '', generate_test_string(i))
41.933375883003464  20  re.sub(r'[\W]+', '', generate_test_string(i))
38.899814646996674  20  pattern_single.sub('', generate_test_string(i))
38.636144253003295  20  pattern_repeat.sub('', generate_test_string(i))
36.201238164998360  20  generate_test_string(i).translate(translation_tb)
49.377356811004574  30  ''.join(c for c in generate_test_string(i) if c.isalnum())
48.408927293996385  30  ''.join(filter(str.isalnum, generate_test_string(i)))
53.901889764994850  30  re.sub(r'[\W]', '', generate_test_string(i))
52.130339455994545  30  re.sub(r'[\W]+', '', generate_test_string(i))
50.061149017004940  30  pattern_single.sub('', generate_test_string(i))
49.366573111998150  30  pattern_repeat.sub('', generate_test_string(i))
46.649754120997386  30  generate_test_string(i).translate(translation_tb)
63.107938601999194  40  ''.join(c for c in generate_test_string(i) if c.isalnum())
65.116287978999030  40  ''.join(filter(str.isalnum, generate_test_string(i)))
71.477421126997800  40  re.sub(r'[\W]', '', generate_test_string(i))
66.027950693998720  40  re.sub(r'[\W]+', '', generate_test_string(i))
63.315361931003280  40  pattern_single.sub('', generate_test_string(i))
62.342320287003530  40  pattern_repeat.sub('', generate_test_string(i))
58.249303059004890  40  generate_test_string(i).translate(translation_tb)
73.810345625002810  50  ''.join(c for c in generate_test_string(i) if c.isalnum())
72.593953348005020  50  ''.join(filter(str.isalnum, generate_test_string(i)))
76.048324580995540  50  re.sub(r'[\W]', '', generate_test_string(i))
75.106637657001560  50  re.sub(r'[\W]+', '', generate_test_string(i))
74.681338128997600  50  pattern_single.sub('', generate_test_string(i))
72.430461594005460  50  pattern_repeat.sub('', generate_test_string(i))
69.394243567003290  50  generate_test_string(i).translate(translation_tb)
Run Code Online (Sandbox Code Playgroud)

str.maketrans&str.translate速度最快,但包含所有非 ASCII 字符。 re.compile&pattern.sub较慢,但在某种程度上比''.join&更快filter


Buv*_*inJ 6

作为此处其他一些答案的衍生,我提供了一种非常简单且灵活的方法来定义您希望将字符串内容限制为的一组字符。在这种情况下,我允许使用字母数字加破折号和下划线。只需PERMITTED_CHARS根据您的用例添加或删除 my 中的字符即可。

PERMITTED_CHARS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-" 
someString = "".join(c for c in someString if c in PERMITTED_CHARS)
Run Code Online (Sandbox Code Playgroud)

  • 不要对容易出现细微错误的允许字符进行硬编码,而是使用 `string.digits + string.ascii_letters + '_-'`。 (3认同)

Ben*_*ard 5

对于一个简单的单行代码(Python 3.0):

''.join(filter( lambda x: x in '0123456789abcdefghijklmnopqrstuvwxyz', the_string_you_want_stripped ))
Run Code Online (Sandbox Code Playgroud)

对于 Python < 3.0:

filter( lambda x: x in '0123456789abcdefghijklmnopqrstuvwxyz', the_string_you_want_stripped )
Run Code Online (Sandbox Code Playgroud)

注意:如果需要,您可以将其他字符添加到允许的字符列表中(例如“0123456789abcdefghijklmnopqrstuvwxyz.,_”)。