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

Mat*_*ips 491 python string immutability

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

for char in line:
    if char in " ?.!/;:":
        line.replace(char,'')
Run Code Online (Sandbox Code Playgroud)

我该怎么做呢?

int*_*ted 589

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

而且,你这样做的方式相对较慢.对于经验丰富的pythonator来说,这也可能有点令人困惑,他们会看到一个双重嵌套的结构,并想一想更复杂的事情正在发生.

从Python 2.6和更新的Python 2.x版本*开始,您可以使用str.translate,(但请继续阅读Python 3的差异):

line = line.translate(None, '!@#$')
Run Code Online (Sandbox Code Playgroud)

或正则表达式替换 re.sub

import re
line = re.sub('[!@#$]', '', line)
Run Code Online (Sandbox Code Playgroud)

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

在Python 3中,字符串是Unicode.你将不得不翻译一点点.kevpie 在其中一个答案的评论中提到了这一点,并在文档中str.translate注明.

调用translateUnicode字符串的方法时,您无法传递我们上面使用的第二个参数.您也不能None作为第一个参数传递,甚至不能传递string.maketrans.相反,您将字典作为唯一参数传递.这个字典将字符的序数值(即调用ord它们的结果)映射到应该替换它们的字符的序数值,或者对我们有用None- 表示它们应该被删除.

所以要用Unicode字符串做上面的舞蹈,你会称之为

translation_table = dict.fromkeys(map(ord, '!@#$'), None)
unicode_line = unicode_line.translate(translation_table)
Run Code Online (Sandbox Code Playgroud)

这里dict.fromkeysmap习惯于简洁地生成包含的字典

{ord('!'): None, ord('@'): None, ...}
Run Code Online (Sandbox Code Playgroud)

更简单,正如另一个答案所说,创建字典:

unicode_line = unicode_line.translate({ord(c): None for c in '!@#$'})
Run Code Online (Sandbox Code Playgroud)

*为了与早期的Pythons兼容,您可以创建一个"null"转换表来代替None:

import string
line = line.translate(string.maketrans('', ''), '!@#$')
Run Code Online (Sandbox Code Playgroud)

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

  • 在python3中,str.translate()不接受第二个参数.所以,你的答案将成为`line.translate({ord(i):我在'!@#$'}中没有) (31认同)
  • 在Python3中,`line.translate`只接受一个参数,第一个解决方案不起作用 (23认同)
  • 上面@naveen的评论对我有用。Pythony 2.7.13。在我的情况下,我想剥离“和'字符:`notes = notes.translate({ord(i):i在'\” \''}中无) (2认同)

gsb*_*bil 207

我在这里忽略了这一点,还是仅仅是以下内容:

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

print string
# result: "abcdef"
Run Code Online (Sandbox Code Playgroud)

把它放在一个循环中:

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

print a
# result: "abcd"
Run Code Online (Sandbox Code Playgroud)

  • 这将在每个循环中创建一个字符串的副本,这可能是不可取的.它也不是很好的Python.在Python中你会像这样循环:`for b in b:a = a.replace(char,"")` (24认同)
  • 使用与系统类重叠的用户定义变量并不是一个好主意.您最好使用变量STRING而不是STR和C而不是CHAR. (2认同)

gho*_*g74 42

>>> line = "abc#@!?efg12;:?"
>>> ''.join( c for c in line if  c not in '?:!/;' )
'abc#@efg12'
Run Code Online (Sandbox Code Playgroud)

  • 如果你有很多禁止的字符,你可以先把它变成一个集合来加速你的代码。`blacklist = set('?:!/;')` 然后 `''.join(c for c in line if c not in blacklist)` (2认同)

Ser*_*ndt 28

re.sub在Python 3.5中易于使用

re.sub('\ |\?|\.|\!|\/|\;|\:', '', line)
Run Code Online (Sandbox Code Playgroud)

>>> import re

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

>>> re.sub('\ |\?|\.|\!|\/|\;|\:', '', line)
'QDoIwriteNo'
Run Code Online (Sandbox Code Playgroud)

说明

正则表达式(正则表达式)中,|是一个逻辑OR并\转义空格和特殊字符,它们可能是实际的正则表达式命令.sub代表替代.


cod*_*k3y 19

对于允许字符串中的某些字符的反向要求,可以使用带有set complement运算符的正则表达式[^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'
Run Code Online (Sandbox Code Playgroud)

python正则表达式文档:

可以通过补充该组来匹配不在范围内的字符.如果该组的第一个字符是'^',则将匹配该组中不存在的所有字符.例如,[^5]将匹配除"5"之外的任何字符,并[^^]匹配除了之外的任何字符 '^'.^如果它不是集合中的第一个字符,则没有特殊含义.


mgo*_*old 18

提问者几乎拥有它.像Python中的大多数东西一样,答案比你想象的要简单.

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

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


Muh*_*uri 14

line = line.translate(None, " ?.!/;:")
Run Code Online (Sandbox Code Playgroud)

  • 类型错误:translate() 只接受一个参数(给定 2 个参数) (3认同)
  • +1使用unicode时,需要设置要删除的转换而不是删除字符串.http://docs.python.org/library/stdtypes.html#str.translate (2认同)

eat*_*kin 10

>>> s = 'a1b2c3'
>>> ''.join(c for c in s if c not in '123')
'abc'
Run Code Online (Sandbox Code Playgroud)

  • 我的回答确实提供了原始问题的解决方案,但我也对我的解决方案可能不理想的反馈感兴趣(也许也是OP).我是否应该创建一个新问题并将其引用为上下文? (2认同)

Gre*_*ill 9

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

for char in line:
    if char in " ?.!/;:":
        line = line.replace(char,'')
Run Code Online (Sandbox Code Playgroud)

  • 这是非常浪费的。您迭代“line”的每个字符并检查该字符是否在要删除的字符集中。如果是,那么您将删除“line”中所有出现的字符,那么为什么还要继续检查“line”中的其余字符并再次检查是否有保证不再存在的字符呢?相反,我建议这样: `for char in " ?.!/;:": line = line.replace(char, "")` 这将有与要删除的字符一样多的迭代次数。[此处更清晰的版本](/sf/answers/4458126151/) (2认同)

小智 9

试试这个:

def rm_char(original_str, need2rm):
    ''' Remove charecters in "need2rm" from "original_str" '''
    return original_str.translate(str.maketrans('','',need2rm))
Run Code Online (Sandbox Code Playgroud)

该方法在Python 3中运行良好

  • 这似乎是这个问题的最佳答案。 (2认同)

Dan*_*kin 8

我很惊讶没有人建议使用内置过滤器功能.

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

    s = "1212edjaq"
Run Code Online (Sandbox Code Playgroud)

假设我们要过滤掉所有不是数字的东西.使用filter builtin方法"...相当于生成器表达式(如果函数(item),则迭代中的项目项目)"[ Python 3 Builtins:Filter ]

    sList = list(s)
    intsList = list(string.digits)
    obj = filter(lambda x: operator.contains(intsList, x), sList)))
Run Code Online (Sandbox Code Playgroud)

在Python 3中,这将返回

    >>  <filter object @ hex>
Run Code Online (Sandbox Code Playgroud)

要获得打印的字符串,

    nums = "".join(list(obj))
    print(nums)
    >> "1212"
Run Code Online (Sandbox Code Playgroud)

我不确定过滤器在效率方面是如何排名的,但是在做列表推导等时知道如何使用它是一件好事.

UPDATE

从逻辑上讲,由于过滤器的工作原理,你也可以使用列表理解,从我所读到的它应该更有效率,因为lambdas是编程功能世界的华尔街对冲基金经理.另一个优点是它是一个不需要任何进口的单线程.例如,使用上面定义的相同字符串's',

      num = "".join([i for i in s if i.isdigit()])
Run Code Online (Sandbox Code Playgroud)

而已.返回将是原始字符串中所有字符的字符串.

如果您有可接受/不可接受字符的特定列表,则只需调整列表理解的"if"部分.

      target_chars = "".join([i for i in s if i in some_list]) 
Run Code Online (Sandbox Code Playgroud)

或者,

      target_chars = "".join([i for i in s if i not in some_list])
Run Code Online (Sandbox Code Playgroud)


ser*_*inc 7

使用filter,你只需要一行

line = filter(lambda char: char not in " ?.!/;:", line)
Run Code Online (Sandbox Code Playgroud)

这会将字符串视为可迭代的,并在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.
Run Code Online (Sandbox Code Playgroud)


BPL*_*BPL 5

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

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

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

在我的盒子里你会得到:

attempt1 2.2334518376057244
attempt2 1.8806643818474513
attempt3 7.214925774955572
attempt4 1.7271184513757465
Run Code Online (Sandbox Code Playgroud)

所以看来尝试4对于这个特定的输入来说是最快的。

  • 您正在“attempt1”中创建一个不必要的“list”,并且为了简单起见,可以将元组重写为“aeiou”(删除“[”和“]”将变成一个生成器而不创建列表)。您在“attemt2”中创建了大量的一次性中间字符串,在“attempt3”中使用了多个正则表达式应用程序,其中您可以一次性使用“r”[aeiou]”。每个都有缺陷 - 很高兴看到不同的做事方式,但也请修复它们,使其成为良好的尝试 (2认同)