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


236

我需要从字符串中删除所有特殊字符,标点符号和空格,以便只有字母和数字。

Answers:


351

这可以不用正则表达式来完成:

>>> 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.

如果您坚持使用正则表达式,则其他解决方案也可以。但是请注意,如果可以在不使用正则表达式的情况下完成此操作,那么这是最好的解决方法。


7
不使用正则表达式的经验是什么原因?
克里斯·杜特罗

@ChrisDutrow正则表达式比python字符串内置函数慢
Diego Navarro

这仅在字符串使用unicode时有效。否则,它会抱怨'str'对象没有属性'isalnum''isnumeric',依此类推。
NeoJi

10
@DiegoNavarro除外,那不是真的,我对isalnum()和regex版本均进行了基准测试,而regex则提高了50-75%
Francisco Couzo

2
另外:“对于8位字符串,此方法取决于语言环境。”!因此,正则表达式的替代品绝对更好!
Antti Haapala '18

232

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

[^A-Za-z0-9]+

这是执行正则表达式替换的Python命令:

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

10
吻:保持简单愚蠢!与非正则表达式解决方案相比,它更短且更易于阅读,并且可能更快。(不过,我会添加一个+量词以提高其效率。)
ridgerunner 2011年

1
这也会删除单词“ great place”->“ greatplace”之间的空格。如何避免呢?
Reihan_amn

5
@Reihan_amn只需在正则表达式中添加一个空格,它就变成:[^A-Za-z0-9 ]+
ostroon

1
@ andy-white您能否在答案中在正则表达式中添加空格?空间不是特殊字符...
Ufos '18

3
我猜想这不适用于áöñ等其他语言的修改字符。对吗?如果是这样,它将是正则表达式吗?
HuLu ViCa

50

较短的方法:

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

如果要在单词和数字之间留空格,请用''代替'


3
_除了在\ w中,并且在此问题的上下文中是特殊字符外。
kkurian

取决于上下文-下划线对于文件名和其他标识符非常有用,以至于我不将其视为特殊字符而是将其视为经过清理的空格。我通常自己使用此方法。
梯队

1
r'\W+'-略微偏离主题(而且非常古怪),但我建议养成一种习惯,所有正则表达式模式都应为原始字符串
Bob Stein

2
此过程不会将下划线(_)视为特殊字符。
萨比尔·艾哈迈德(Mr. Sabbir Ahmed)

30

看到这一点之后,我有兴趣通过找出执行时间最短的方法来扩展所提供的答案,因此我仔细检查了一些建议的答案,并timeit对照了两个示例字符串:

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

例子1

'.join(e for e in string if e.isalnum())

  • string1 -结果:10.7061979771
  • string2 -结果:7.77832597694

例子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的速度可以比示例13倍。


@kkurian如果您阅读了我的答案的开头,那么这只是上面先前提出的解决方案的比较。您可能想对原始答案发表评论... stackoverflow.com/a/25183802/2560922
mbeacom '16

哦,我知道你要去哪里了。做完了!
kkurian

1
处理大型语料库时,必须考虑示例3。
HARSH NILESH PATHAK

有效!感谢您的注意。
mbeacom

可你我的回答比较''.join([*filter(str.isalnum, string)])
Grijesh肖汉

22

Python 2. *

我认为filter(str.isalnum, string)效果很好

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

Python 3. *

在Python3中,filter( )函数将返回一个可迭代的对象(而不是上面的字符串)。必须重新加入以从itertable中获取字符串:

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

或通过list加入使用(不确定,但可以很快

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

注意:[*args]Python> = 3.5中解压缩有效


4
@Alexey正确,在python3 mapfilter,并reduce 返回可迭代的对象。仍然在Python3 +中,我会更喜欢 ''.join(filter(str.isalnum, string)) (或在join use中传递列表''.join([*filter(str.isalnum, string)]))而不是可接受的答案。
Grijesh Chauhan

我不确定至少在阅读''.join(filter(str.isalnum, string))方面是否有所改进filter(str.isalnum, string)。这真的是Pythreenic(是的,您可以使用该方法)吗?
无产阶级者'18

1
@TheProletariat点是只是filter(str.isalnum, string)不Python3返回字符串filter( )在Python3返回迭代器,而不是不同的Python-2参数类型+。
Grijesh肖汉

@GrijeshChauhan,我认为您应该更新答案以同时包含Python2和Python3建议。
mwfearnley

18
#!/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

您可以添加更多特殊字符,然后将其替换为“”,则表示没有任何意义,即它们将被删除。


16

与使用正则表达式的其他所有人不同,我将尝试排除想要的每个字符,而不是明确枚举不需要的字符。

例如,如果我只需要'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())

9

假设您要使用正则表达式,并且想要/需要支持2to3的Unicode识别2.x代码:

>>> 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'
>>>


6

最通用的方法是使用unicodedata表的“类别”,该表对每个单个字符进行分类。例如,以下代码根据其类别仅过滤可打印字符:

import unicodedata
# strip of crap characters (based on the Unicode database
# categorization:
# http://www.sql-und-xml.de/unicode-database/#kategorien

PRINTABLE = set(('Lu', 'Ll', 'Nd', 'Zs'))

def filter_non_printable(s):
    result = []
    ws_last = False
    for c in s:
        c = unicodedata.category(c) in PRINTABLE and c or u'#'
        result.append(c)
    return u''.join(result).replace(u'#', u' ')

查看上面所有相关类别的给定URL。当然,您也可以按标点符号类别进行过滤。


有什么用的$,在每一行的结束?
约翰·马钦

如果是复制和粘贴问题,那您应该解决它吗?
Olli 2012年

5

string。标点符号包含以下字符:

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

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

import string

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

输出:

'This is A test'

4

使用翻译:

import string

def clean(instr):
    return instr.translate(None, string.punctuation + ' ')

警告:仅适用于ASCII字符串。


版本差异?我得到TypeError: translate() takes exactly one argument (2 given)py3.4
马特·威尔基(Matt wilkie)

1
import re
my_string = """Strings are amongst the most popular data types in Python. We can create the strings by enclosing characters in quotes. Python treats single quotes the 

与双引号相同。“”“

# if we need to count the word python that ends with or without ',' or '.' at end

count = 0
for i in text:
    if i.endswith("."):
        text[count] = re.sub("^([a-z]+)(.)?$", r"\1", i)
    count += 1
print("The count of Python : ", text.count("python"))

0
import re
abc = "askhnl#$%askdjalsdk"
ddd = abc.replace("#$%","")
print (ddd)

您将看到的结果为

'askhnlaskdjalsdk


4
等待...。您导入re但从未使用过。您的replace条件仅适用于该特定字符串。如果您的字符串是abc = "askhnl#$%!askdjalsdk"怎么办?我认为除了#$%模式之外,其他任何方法都不会起作用。可能想要对其进行调整
JChao

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.