在Python中从字符串中删除特定字符

我正在尝试使用Python从字符串中删除特定字符。这是我现在使用的代码。不幸的是,它似乎对字符串没有任何作用。

for char in line:
if char in " ?.!/;:":
line.replace(char,'')

我如何正确地做到这一点?

1776440 次浏览

字符串在Python中是不可变的。replace方法在替换后返回一个新字符串。尝试:

for char in line:
if char in " ?.!/;:":
line = line.replace(char,'')

这与您的原始代码相同,只是在循环中添加了对line的赋值。

请注意,字符串replace()方法替换字符串中出现的字符的所有,因此您可以通过对要删除的每个字符使用replace()来做得更好,而不是循环遍历字符串中的每个字符。

Python中的字符串是不可变(不能更改)。因此,line.replace(...)的效果只是创建一个新字符串,而不是更改旧字符串。您需要重新绑定(分配)它给line,以便该变量采用新值,并删除这些字符。

而且,你这样做的方式会比较慢,相对而言。对于有经验的Pythonators来说,这也可能有点混乱,他们会看到一个双重嵌套的结构,并认为有更复杂的事情正在发生。

从Python 2.6和更新的Python 2. x版本*开始,您可以改为使用str.translate,(请参阅下面的Python 3答案):

line = line.translate(None, '!@#$')

或用re.sub替换正则表达式

import re
line = re.sub('[!@#$]', '', line)

括号中的字符构成字符类line中属于该类的任何字符都将替换为sub的第二个参数:空字符串。

python3回答

在Python 3中,字符串是Unicode。您必须稍微不同地翻译。kevpy在其中一个答案的评论中提到了这一点,并在留档str.translate中注明。

当调用Unicode字符串的translate方法时,您不能传递我们上面使用的第二个参数。您也不能传递None作为第一个参数。相反,您传递一个翻译表(通常是字典)作为唯一的参数。此表将字符的序数值(即对其调用ord的结果)映射到应该替换它们的字符的序数值,或者-对我们有用-None表示应该删除它们。

因此,要使用Unicode字符串执行上述舞蹈,您将调用以下内容

translation_table = dict.fromkeys(map(ord, '!@#$'), None)
unicode_line = unicode_line.translate(translation_table)

这里dict.fromkeysmap用于简洁地生成包含

{ord('!'): None, ord('@'): None, ...}

更简单的是,作为另一个答案是,在原地创建翻译表:

unicode_line = unicode_line.translate({ord(c): None for c in '!@#$'})

或者,正如约瑟夫·李所提出的,使用str.maketrans创建相同的翻译表:

unicode_line = unicode_line.translate(str.maketrans('', '', '!@#$'))

*为了与早期Python兼容,您可以创建一个“null”转换表来代替None

import string
line = line.translate(string.maketrans('', ''), '!@#$')

这里string.maketrans用于创建翻译表,它只是一个包含序数值为0到255的字符的字符串。

line = line.translate(None, " ?.!/;:")
>>> line = "abc#@!?efg12;:?"
>>> ''.join( c for c in line if  c not in '?:!/;' )
'abc#@efg12'

我在这里错过了重点,还是只是以下几点:

string = "ab1cd1ef"
string = string.replace("1", "")


print(string)
# result: "abcdef"

把它放在一个循环中:

a = "a!b@c#d$"
b = "!@#$"
for char in b:
a = a.replace(char, "")


print(a)
# result: "abcd"

就像Python中的大多数东西一样,答案比你想象的要简单。

>>> line = "H E?.LL!/;O:: "
>>> for char in ' ?.!/;:':
...  line = line.replace(char,'')
...
>>> print line
HELLO

您不必执行嵌套的if/for循环,但您确实需要单独检查每个字符。

对于字符串中允许某些字符的逆要求,您可以使用带有集合补码运算符[^ABCabc]的正则表达式。例如,要删除除ascii字母、数字和连字符之外的所有内容:

>>> import string
>>> import re
>>>
>>> phrase = '  There were "nine" (9) chick-peas in my pocket!!!      '
>>> allow = string.letters + string.digits + '-'
>>> re.sub('[^%s]' % allow, '', phrase)


'Therewerenine9chick-peasinmypocket'

来自python正则表达式留档

不在一个范围内的字符可以通过互补来匹配 集合。如果集合的第一个字符是'^',则所有字符 不在集合中的将被匹配。例如,[^5]将匹配 除“5”之外的任何字符,[^^]将匹配除“5”之外的任何字符 ^没有特殊的意义,如果它不是第一个字符 设置。

#!/usr/bin/python
import re


strs = "how^ much for{} the maple syrup? $20.99? That's[] ricidulous!!!"
print strs
nstr = re.sub(r'[?|$|.|!|a|b]',r' ',strs)#i have taken special character to remove but any #character can be added here
print nstr
nestr = re.sub(r'[^a-zA-Z0-9 ]',r'',nstr)#for removing special character
print nestr

这个怎么样:

def text_cleanup(text):
new = ""
for i in text:
if i not in " ?.!/;:":
new += i
return new

下面一个…使用正则表达式概念…

ipstring ="text with symbols!@#$^&*( ends here"
opstring=''
for i in ipstring:
if i.isalnum()==1 or i==' ':
opstring+=i
pass
print opstring

您还可以使用一个函数来使用列表替换不同类型的正则表达式或其他模式。有了它,您可以混合正则表达式、字符类和真正基本的文本模式。当你需要替换很多元素时,它非常有用,比如超文本标记语言。

*注意:适用于Python 3. x

import re  # Regular expression library




def string_cleanup(x, notwanted):
for item in notwanted:
x = re.sub(item, '', x)
return x


line = "<title>My example: <strong>A text %very% $clean!!</strong></title>"
print("Uncleaned: ", line)


# Get rid of html elements
html_elements = ["<title>", "</title>", "<strong>", "</strong>"]
line = string_cleanup(line, html_elements)
print("1st clean: ", line)


# Get rid of special characters
special_chars = ["[!@#$]", "%"]
line = string_cleanup(line, special_chars)
print("2nd clean: ", line)

在函数string_cleanup中,它将字符串x和不想要的列表作为参数。对于元素或模式列表中的每个项目,如果需要替换,就会完成。

输出:

Uncleaned:  <title>My example: <strong>A text %very% $clean!!</strong></title>
1st clean:  My example: A text %very% $clean!!
2nd clean:  My example: A text very clean
>>> s = 'a1b2c3'
>>> ''.join(c for c in s if c not in '123')
'abc'

我使用的方法可能不会那么有效,但它非常简单。我可以一次删除不同位置的多个字符,使用切片和格式化。 举个例子:

words = "things"
removed = "%s%s" % (words[:3], words[-1:])

这将导致“删除”持有“this”一词。

格式对于在打印字符串中途打印变量非常有帮助。它可以使用%后跟变量的数据类型插入任何数据类型;所有数据类型都可以使用%s,浮点数(又名小数)和整数可以使用%d

切片可用于复杂地控制字符串。当我放字数[: 3]时,它允许我选择字符串中从开始(冒号在数字之前,这意味着“从开始到”)到第4个字符(它包括第4个字符)的所有字符。3等于到第4个位置的原因是因为Python从0开始。然后,当我放word[-1:]时,它意味着最后第二个字符(冒号在数字后面)。放-1将使Python从最后一个字符开始计数,而不是第一个。同样,Python将从0开始。所以,word[-1:]基本上意味着'从倒数第二个字符到字符串的末尾。

所以,通过切断我想要删除的字符之前的字符和之后的字符并将它们夹在一起,我可以删除不需要的字符。把它想象成香肠。中间很脏,所以我想摆脱它。我简单地切断了我想要的两端,然后把它们放在一起,中间没有不需要的部分。

如果我想删除多个连续字符,我只需在[](切片部分)中移动数字。或者如果我想从不同位置删除多个字符,我可以一次简单地将多个切片夹在一起。

示例:

 words = "control"
removed = "%s%s" % (words[:2], words[-2:])

删除等于“酷”。

words = "impacts"
removed = "%s%s%s" % (words[1], words[3:5], words[-1])

删除等于“macs”。

在这种情况下,[3:5]表示职位 3处的字符到职位 5处的字符(不包括最终位置的字符)。

记住,Python从0开始计数,所以你也需要。

这是我的Python 2/3兼容版本。由于翻译API已更改。

def remove(str_, chars):
"""Removes each char in `chars` from `str_`.


Args:
str_: String to remove characters from
chars: String of to-be removed characters


Returns:
A copy of str_ with `chars` removed


Example:
remove("What?!?: darn;", " ?.!:;") => 'Whatdarn'
"""
try:
# Python2.x
return str_.translate(None, chars)
except TypeError:
# Python 3.x
table = {ord(char): None for char in chars}
return str_.translate(table)

我很惊讶还没有人推荐使用内置的过滤器函数。

    import operator
import string # only for the example you could use a custom string


s = "1212edjaq"

假设我们想过滤掉所有不是数字的东西。使用过滤器内置方法“…等效于生成器表达式(可迭代if函数(项目)中的项目)”[Python 3内置:过滤器]

    sList = list(s)
intsList = list(string.digits)
obj = filter(lambda x: operator.contains(intsList, x), sList)))

在Python 3中返回

    >>  <filter object @ hex>

要获得打印的字符串,

    nums = "".join(list(obj))
print(nums)
>> "1212"

我不确定过滤器在效率方面的排名如何,但在进行列表理解等时知道如何使用是一件好事。

更新

从逻辑上讲,由于过滤器的工作原理,你也可以使用列表理解,根据我所读到的,它应该更有效,因为lambda是编程函数世界的华尔街对冲基金经理。另一个好处是它是一个不需要任何导入的单行代码。例如,使用上面定义的相同字符串s',

      num = "".join([i for i in s if i.isdigit()])

就是这样。返回将是一个包含原始字符串中数字的所有字符的字符串。

如果您有一个特定的可接受/不可接受字符列表,您只需要调整列表理解的“if”部分。

      target_chars = "".join([i for i in s if i in some_list])

或者,

      target_chars = "".join([i for i in s if i not in some_list])

在python3.5

例如,

os.rename(file_name, file_name.translate({ord(c): None for c in '0123456789'}))

从字符串中删除所有数字

即使是下面的方法工作

line = "a,b,c,d,e"
alpha = list(line)
while ',' in alpha:
alpha.remove(',')
finalString = ''.join(alpha)
print(finalString)

输出:abcde

re.sub正则表达式

从Python 3.5开始,使用正则表达式re.sub进行替换变得可用:

import re
re.sub('\ |\?|\.|\!|\/|\;|\:', '', line)

示例

import re
line = 'Q: Do I write ;/.??? No!!!'
re.sub('\ |\?|\.|\!|\/|\;|\:', '', line)


'QDoIwriteNo'

补充说明

正则表达式(regex)中,|是逻辑OR,\转义可能是实际正则表达式命令的空格和特殊字符。而sub在本例中代表替代,,空字符串''

使用filter,您只需要一行

line = filter(lambda char: char not in " ?.!/;:", line)

这将字符串视为可迭代的,如果lambda返回True,则检查每个字符:

>>> help(filter)
Help on built-in function filter in module __builtin__:


filter(...)
filter(function or None, sequence) -> list, tuple, or string


Return those items of sequence for which function(item) is true.  If
function is None, return the items that are true.  If sequence is a tuple
or string, return the same type, else return a list.

试试这个:

def rm_char(original_str, need2rm):
''' Remove charecters in "need2rm" from "original_str" '''
return original_str.translate(str.maketrans('','',need2rm))

这个方法在Python 3中运行良好

递归分割: s=string; chars=要删除的字符

def strip(s,chars):
if len(s)==1:
return "" if s in chars else s
return strip(s[0:int(len(s)/2)],chars) +  strip(s[int(len(s)/2):len(s)],chars)

例子:

print(strip("Hello!","lo"))    #He!

以下是实现此任务的一些可能方法:

def attempt1(string):
return "".join([v for v in string if v not in ("a", "e", "i", "o", "u")])




def attempt2(string):
for v in ("a", "e", "i", "o", "u"):
string = string.replace(v, "")
return string




def attempt3(string):
import re
for v in ("a", "e", "i", "o", "u"):
string = re.sub(v, "", string)
return string




def attempt4(string):
return string.replace("a", "").replace("e", "").replace("i", "").replace("o", "").replace("u", "")




for attempt in [attempt1, attempt2, attempt3, attempt4]:
print(attempt("murcielago"))

PS:而不是使用 " ?.! /;:" 例子使用元音……是的,"mucielago"是西班牙语单词说蝙蝠……有趣的词,因为它包含所有的元音:)

PS2:如果你对性能感兴趣,你可以用一个简单的代码来衡量这些尝试,比如:

import timeit




K = 1000000
for i in range(1,5):
t = timeit.Timer(
f"attempt{i}('murcielago')",
setup=f"from __main__ import attempt{i}"
).repeat(1, K)
print(f"attempt{i}",min(t))

在我的盒子里你会得到:

attempt1 2.2334518376057244
attempt2 1.8806643818474513
attempt3 7.214925774955572
attempt4 1.7271184513757465

因此,对于这个特定的输入来说,尝试4似乎是最快的。

您可以使用re模块的正则表达式替换。使用^表达式允许您从字符串中准确选择所需的内容。

    import re
text = "This is absurd!"
text = re.sub("[^a-zA-Z]","",text) # Keeps only Alphabets
print(text)

输出将是“ThisiSabsurd”。只有在^符号之后指定的东西才会出现。

#对于目录中的每个文件,重命名filename

   file_list = os.listdir (r"D:\Dev\Python")


for file_name in file_list:


os.rename(file_name, re.sub(r'\d+','',file_name))

字符串方法replace不修改原始字符串。它保留原始并返回修改后的副本。

你想要的是:line = line.replace(char,'')

def replace_all(line, )for char in line:
if char in " ?.!/;:":
line = line.replace(char,'')
return line

但是,每次删除字符时都创建一个新字符串是非常低效的。我推荐以下方法:

def replace_all(line, baddies, *):
"""
The following is documentation on how to use the class,
without reference to the implementation details:


For implementation notes, please see comments begining with `#`
in the source file.


[*crickets chirp*]


"""


is_bad = lambda ch, baddies=baddies: return ch in baddies
filter_baddies = lambda ch, *, is_bad=is_bad: "" if is_bad(ch) else ch
mahp = replace_all.map(filter_baddies, line)
return replace_all.join('', join(mahp))


# -------------------------------------------------
# WHY `baddies=baddies`?!?
#     `is_bad=is_bad`
# -------------------------------------------------
# Default arguments to a lambda function are evaluated
# at the same time as when a lambda function is
# **defined**.
#
# global variables of a lambda function
# are evaluated when the lambda function is
# **called**
#
# The following prints "as yellow as snow"
#
#     fleece_color = "white"
#     little_lamb = lambda end: return "as " + fleece_color + end
#
#     # sometime later...
#
#     fleece_color = "yellow"
#     print(little_lamb(" as snow"))
# --------------------------------------------------
replace_all.map = map
replace_all.join = str.join

如果您希望使用ASCII代码使您的字符串只是允许的字符,您可以使用这段代码:

for char in s:
if ord(char) < 96 or ord(char) > 123:
s = s.replace(char, "")

它将删除超出a…… z甚至大小写的所有字符。