从字符串中删除所有特殊字符、标点符号和空格。

399

我需要将一个字符串中的所有特殊字符、标点符号和空格都去除,这样我就只剩下字母和数字了。

19个回答

549

这可以在不使用正则表达式的情况下完成:

>>> string = "Special $#! characters   spaces 888323"
>>> ''.join(e for e in string if e.isalnum())
'Specialcharactersspaces888323'
你可以使用 str.isalnum 方法。
S.isalnum() -> bool

Return True if all characters in S are alphanumeric
and there is at least one character in S, False otherwise.

如果您坚持使用正则表达式,其他解决方案也可以胜任。但请注意,如果不使用正则表达式也可以完成任务,那就是最好的方法。


13
为什么不建议将正则表达式作为常规方法? - Chris Dutrow
只有当字符串是unicode时,此方法才有效。否则会出现“str”对象没有“isalnum”、“isnumeric”等属性的错误提示。 - NeoJi
18
除非那是不真实的,我对isalnum()和正则表达式版本进行了基准测试,而且正则表达式版本更快,速度提高了50-75%。 - Francisco
1
在Python3中尝试过这个 - 它接受Unicode字符,所以对我来说没用。尝试使用字符串=“B223323\§§§$3\u445454”作为示例。结果是什么?'B2233233䑔54' - 576i
4
另外,需要注意的是:"对于8位字符串,该方法依赖于locale(语言环境)"!因此,使用正则表达式是更好的选择! - Antti Haapala -- Слава Україні
显示剩余2条评论

393

这是一个正则表达式,用于匹配不是字母或数字的字符:

[^A-Za-z0-9]+

这里是用Python进行正则表达式替换的命令:

re.sub('[^A-Za-z0-9]+', '', mystring)

28
KISS:保持简单愚蠢!这比非正则表达式的解决方案更短,更易于阅读,并且可能更快。 (但是,我会添加一个“+”限定符以稍微提高效率。) - ridgerunner
7
这也会移除单词之间的空格,例如,“great place” 会变成“greatplace”。如何避免这种情况发生? - Reihan_amn
27
@Reihan_amn 只需在正则表达式中添加一个空格,即可变为:[^A-Za-z0-9 ]+ - sougonde
7
我猜这对于其它语言中的修改过的字符,比如áöñ等无法运作。如果是这样,那么匹配它们的正则表达式会是什么? - HuLu ViCa
10
这对于西班牙语、德语、丹麦语和其他语言无效。 - tommy.carstensen
显示剩余4条评论

79

更简洁的方法:

import re
cleanString = re.sub('\W+','', string )

如果你想在单词和数字之间加上空格,请将''替换为' '


6
除了 _ 在 \w 中并且在此问题的上下文中是一个特殊字符之外,其余都翻译为“除了”。 - kkurian
根据上下文而定——下划线对于文件名和其他标识符非常有用,以至于我不将其视为特殊字符,而是将其视为经过消毒的空格。我自己通常也使用这种方法。 - Echelon
6
r'\W+' - 稍微偏题(而且非常迂腐),但我建议所有正则表达式模式都使用原始字符串的习惯。 - Bob Stein
5
该程序不将下划线(_)视为特殊字符。 - Md. Sabbir Ahmed
2
一个简单的更改也可以去除下划线:使用r"[^A-Za-z]+"代替r"\W+" - Tomerikoo
不客气!我得到的大部分观点都来自这个答案 :) - tuxErrante

72

简要概述

我计时了提供的答案。

import re
re.sub('\W+','', string)

相对于提供的其他最快答案,通常会快3倍

使用此选项时应注意。某些特殊字符(例如ø)可能无法使用此方法剥离。


看到这个,我对提供的答案进行了扩展,找出哪个执行时间最短,因此我检查了一些提议的答案,并使用timeit针对两个示例字符串:

  • string1 = 'Special $#! characters spaces 888323'
  • string2 = 'how much for the maple syrup? $20.99? That s ridiculous!!!'

示例1

'.join(e for e in string if e.isalnum())
  • string1 - 结果:10.7061979771
  • string2 - 结果:7.78372597694

例子 2

import re
re.sub('[^A-Za-z0-9]+', '', string)
  • string1 - 结果:7.10785102844
  • string2 - 结果:4.12814903259

示例 3

import re
re.sub('\W+','', string)
  • string1 - 结果:3.11899876595
  • string2 - 结果:2.78014397621

上述结果是通过对repeat(3, 2000000)的平均值返回最低结果得出的。

示例3可以比示例1快3倍。


@kkurian 如果您阅读我的回答开头,这只是对先前提出的解决方案的比较。您可能想评论原始答案... https://dev59.com/Zm025IYBdhLWcg3wtoVA#25183802 - mbeacom
哦,我明白你的意思了。完成! - kkurian
1
在处理大语料库时,必须考虑到示例3。 - HARSH NILESH PATHAK
1
第三个解决方案没有移除“ø”,但第二个解决方案确实移除了它。 - MehmedB
@TanmeyRawal 你试过这个吗:re.sub('\W+','', string)?它可以去除空格。 - mbeacom
显示剩余4条评论

32

Python 2.*

我认为只需要使用filter(str.isalnum, string)即可。

In [20]: filter(str.isalnum, 'string with special chars like !,#$% etcs.')
Out[20]: 'stringwithspecialcharslikeetcs'

Python 3.*

在Python3中,filter()函数会返回一个可迭代对象(与上文不同,它不返回字符串)。必须使用join方法将其转换为字符串:

''.join(filter(str.isalnum, string)) 

或者在join中传递list时使用(不确定但可能会快一些)

''.join([*filter(str.isalnum, string)])

注意:在Python >= 3.5中,[*args]表示解包参数的语法是有效的。


4
@Alexey 正确,Python3中的 mapfilterreduce 返回迭代对象。在Python3+中,我仍然更喜欢使用 ''.join(filter(str.isalnum, string))(或者如果要将列表传递给 join,则使用 ''.join([*filter(str.isalnum, string)]))而不是接受的答案。 - Grijesh Chauhan
我不确定''.join(filter(str.isalnum, string))相对于filter(str.isalnum, string)来说是否更好,至少在阅读上是这样的。这真的是Pythonic(是的,你可以用这个词)的做法吗? - TheProletariat
1
@TheProletariat 重点是在Python3中,仅使用*filter(str.isalnum, string)*不能像Python2一样返回字符串,因为Python3中的filter()返回迭代器而不是参数类型。 - Grijesh Chauhan
1
@GrijeshChauhan,我认为你应该更新你的答案,包括你对Python2和Python3的建议。 - mwfearnley

27
#!/usr/bin/python
import re

strs = "how much for the maple syrup? $20.99? That's ricidulous!!!"
print strs
nstr = re.sub(r'[?|$|.|!]',r'',strs)
print nstr
nestr = re.sub(r'[^a-zA-Z0-9 ]',r'',nstr)
print nestr

您可以添加更多的特殊字符,这些字符将被替换为''表示没有意义,即它们将被删除。


20

string.punctuation包含以下字符:

'!"#$%&\'()*+,-。/:;< =>?@[\\]^_`{|}~'

您可以使用translate和maketrans函数将标点符号映射为空值(替换)。

import string

'This, is. A test!'.translate(str.maketrans('', '', string.punctuation))

输出:

'This is A test'

19

与其他人使用正则表达式的方式不同,我会尝试排除每个不是我想要的字符,而不是明确列举我不想要的内容。

例如,如果我只想要从'a到z'(大写和小写)以及数字的字符,我会排除所有其他字符:

import re
s = re.sub(r"[^a-zA-Z0-9]","",s)
这意味着“用空字符串替换掉不是数字、在'a到z'或'A到Z'范围内的字符”。事实上,如果你在正则表达式的第一位插入特殊字符^,你会得到否定结果。额外的提示:如果你还需要将结果转换为小写,只要现在找不到任何大写字母,你就可以使正则表达式变得更快、更容易。
import re
s = re.sub(r"[^a-z0-9]","",s.lower())

15
s = re.sub(r"[-()\"#/@;:<>{}`+=~|.!?,]", "", s)

10
假设您想使用正则表达式并且需要具有Unicode感知能力的2.x代码,同时也需要支持2to3转换:
>>> import re
>>> rx = re.compile(u'[\W_]+', re.UNICODE)
>>> data = u''.join(unichr(i) for i in range(256))
>>> rx.sub(u'', data)
u'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\xaa\xb2 [snip] \xfe\xff'
>>>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接