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


545

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

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

如何正确执行此操作?


23
已经过去5年了,但是如何使用该filter函数和Lambda表达式:filter(lambda ch: ch not in " ?.!/;:", line)。我认为也非常简洁高效。当然,它将返回一个新字符串,您必须为其分配一个名称。
约翰·雷德

3
@JohnRed:实际上,它返回一个迭代器,该迭代器返回一个字符列表,但是如果您将其放入答案中,我们中的一些人将很乐意对其进行投票。
比尔·贝尔


@BillBell:PS:它是Python3中的迭代器,是Python2中的字符串,元组或列表
serv-inc

Answers:


624

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

而且,相对而言,您的操作方式会比较缓慢。这也可能会使经验丰富的pythonator感到有些困惑,他们将看到双重嵌套的结构,并暂时认为会发生一些更复杂的事情。

从Python 2.6和更高版本的Python 2.x版本*开始,您可以改用str.translate,(但请继续阅读Python 3的不同之处):

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

或将正则表达式替换为 re.sub

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

方括号内的字符构成一个字符类line该类中的所有字符都被替换为第二个参数sub:空字符串。

在Python 3中,字符串是Unicode。您必须进行一些不同的翻译。kevpie在对其中一个答案的评论中提到了这一点,并在的文档中str.translate对此进行了注明。

当调用translateUnicode字符串的方法时,您不能传递上面使用的第二个参数。您也不能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兼容,您可以创建一个“空”转换表来代替None

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

string.maketrans是用来创建转换表的,它只是一个字符串,其中包含序号为0到255的字符。


26
在Python3中,line.translate仅接受一个参数,第一个解决方案将不起作用
marczoid 2012年

33
在python3中,str.translate()不采用第二个参数。因此,您的答案将变为 line.translate({ord(i):None for i in '!@#$'})
naveen 2014年

1
与任何其他字符相同。Python使您可以使用单引号或双引号对。因此,您只需要编写"'"字符集即可。
2015年

2
上面@naveen的评论对我有用。Pythony 2.7.13。以我notes = notes.translate({ord(i):None for i in '\"\''})
为例,

1
在Python 3中,您可以使用unicode_line.translate(str.maketrans('', '', '!@#$'))。或unicode_line.translate(dict.fromkeys(map(ord, '!@#$')))
马丁·皮特斯

234

我是否在这里遗漏了要点,或者只是以下内容:

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"

26
这将在每个循环中复制字符串,这可能是不希望的。同样不是很好的Python。在Python中,您应该像这样循环:for char in b: a=a.replace(char,"")
elgehelge 2014年

2
使用与系统类重叠的用户定义变量不是一个好主意。您最好使用变量STRING代替STR,使用C代替CHAR。
Ayrat

需要string=string.replace("1","")代替。您在示例的循环部分中对此进行了说明,但是大多数人直到对这样一个简单的问题先弄一点代码后,才会对您的答案有那么深入的了解。
CodeMed19年

一个好的解决方案,但不如其他解决方案那么出色。
史蒂夫

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

使用另一个字符串定界符,例如“''或“
ALisboa

1
如果您有很多禁止使用的字符,则可以通过将其首先设置为一组来加快代码的速度。blacklist = set('?:!/;')然后''.join(c for c in line if c not in blacklist)
鲍里斯(Boris)

32

re.sub从Python 3.5开始具有正则表达式

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

>>> import re

>>> line = 'Q: Do I write ;/.??? No!!!'

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

说明

正则表达式(regex)中,|它是逻辑OR,并\转义可能是实际regex命令的空格和特殊字符。而sub代表替换,在这种情况下为空字符串''


22

对于允许在字符串中使用某些字符的相反要求,可以将正则表达式与集合补码运算符配合使用[^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”以外的任何字符,并将匹配除以外的[^^]任何字符 '^'^如果不是集合中的第一个字符,则没有特殊含义。


19

询问者几乎拥有了它。像Python中的大多数事物一样,答案比您想象的要简单。

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

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


是的,我知道,可能为时已晚,但是如果您逃脱了,它应该可以工作。像这样:line = line.replace('`','')继续阅读:Learnpythonthehardway.org/book/ex10.html
Aiyion.Prime,2016年

这可能不起作用,因为您正在为每个字符分配一个新的字符串
OneCricketeer


11
>>> s = 'a1b2c3'
>>> ''.join(c for c in s if c not in '123')
'abc'

2
我的回答确实为原始问题提供了解决方案,但是我也对反馈(为什么还有OP)感兴趣,以了解为什么我的解决方案可能不是理想的。我是否应该创建一个新问题并引用它作为背景?
eatkin

这得到我的投票。简洁的Python
Steve

9

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

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

如何遍历行并同时对其进行修改?
eumiro

1
@eumiro:迭代在原始上进行 line
Greg Hewgill

很高兴知道!因此,如果我遍历数组,则遍历原始数组。不可能在迭代器上进行迭代。
eumiro 2010年

9

令我惊讶的是,还没有人建议使用内置过滤器功能。

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

    s = "1212edjaq"

假设我们要过滤掉所有不是数字的内容。使用过滤器内置方法“ ...等效于生成器表达式(如果函数(item),则为可迭代的项目项)” [ 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])

没有理由使用operator.contains,如果您使用的是lambda反正。lambda x: operator.contains(intsList, x)应该是拼写的lambda x: x in intsList,或者如果您尝试获得C级检查,intsList.__contains__(一点也不lambda)可以解决问题。
ShadowRanger

8

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

4

这是完成此任务的一些可能方法:

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:示例中使用的是元音...,而不是“?。!/ ;:”,是的,“ murcielago”是西班牙语中用来说蝙蝠的单词...有趣的词,因为它包含所有元音

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

因此,对于这种特定输入,似乎try4是最快的尝试。


1
您正在创建一个不必要的数组listattempt1并且"aeiou"为了简单起见,可以将其重写为元组(删除[并且]将变成一个生成器,而无需创建列表)。您可以在中创建大量的一次性中介字符串attemt2attempt3并且可以r'[aeiou]'在一处使用regex的多个应用程序。每个人都有缺点-它很高兴看到不同的方式做事情,但请解决这些问题是很好的尝试,以及
帕特里克Artner

1
@PatrickArtner你是完全正确的……从我想到的数十种方法中,我选择了较慢的方法(希望向OP展示一些最简单的方法)……也就是说,在你完成之后伙计们关闭了另一个线程,我已经失去了为这个已经回答的旧线程付出更多努力的动力,所以... :)。谢谢你的观点。
BPL

@PatrickArtner好吧……仅出于缘故添加了一个新的“ attempt4”……尚未测量,但我认为应该是更快的
BPL

1
@PatrickArtner编辑... try4是从少量尝试中最快的。无论如何,我不会在这些东西上浪费更多的时间:)
BPL

3

这是我的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)

我会dict.fromkeys(map(ord, '!@#$'))用来创建地图。
马丁·彼得斯

map通常比列表/字典/集合/生成器理解的可读性差。如此之多以至于Guido想要从语言中删除。使用fromkeys也有点聪明,需要文档检查。
Bryce Guinta '17

1
@MartijnPieters:对于Python 3,它应该只是,它可以一次性str.maketrans('', '', chars)处理ord转换和dict构造(更不用说在意图上更明显了,因为它是与配对设计的str.translate)。
ShadowRanger

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

你是说语音标记吗?re具有反斜杠以转义代码并视为'字符串。docs.python.org/2/library/re.html
JasTonAChair

1

这个怎么样:

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

1
您能否详细说明您的答案,并提供有关您提供的解决方案的更多描述?
abarisone

添加到列表中,然后使用连接比连接更有效
OneCricketeer

1

您还可以使用一个函数,以使用列表替换其他种类的正则表达式或其他模式。这样,您就可以混合使用正则表达式,字符类和真正的基本文本模式。当您需要替换许多HTML元素时,它非常有用。

*注意:适用于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

1

我使用的方法可能无法有效地工作,但是它非常简单。我可以使用切片和格式化功能一次删除不同位置的多个字符。这是一个例子:

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

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

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

切片可用于对字符串的复杂控制。当我输入words [:3]时,它允许我从字符串的开头选择所有字符(冒号在数字之前,这意味着“从开头到”)到第四个字符(包括第四个字符)字符)。之所以3等于第4位是因为Python从0开始。然后,当我将word [-1:]放到最后时,倒数第二个字符(冒号在数字后面)。放置-1将使Python从最后一个字符开始计数,而不是从第一个字符开始计数。同样,Python将从0开始。因此,单词[-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开始计数,因此您也需要这样做。


0

试试这个:

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

此方法在python 3.5.2中很好用


0

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

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

输出为“ Thisisabsurd”。仅出现在^符号后指定的内容。


0

字符串方法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

-1

下面的一个..不使用正则表达式的概念..

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

-1

在Python 3.5中

例如,

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

从字符串中删除所有数字


-1

你可以使用设置

    charlist = list(set(string.digits+string.ascii_uppercase) - set('10IO'))
    return ''.join([random.SystemRandom().choice(charlist) for _ in range(passlen)])

给出答案时,最好对原因做出一些解释
斯蒂芬·劳奇

-1

递归拆分: 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!

-1

#为目录中的每个文件重命名文件名

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

   for file_name in file_list:

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

-1

即使是以下方法也可以

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

输出: abcde


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.