我需要替换一些字符如下:&➔\&,#➔\#,…

我的编码如下,但我想应该有更好的方法。有提示吗?

strs = strs.replace('&', '\&')
strs = strs.replace('#', '\#')
...

当前回答

>>> a = '&#'
>>> print a.replace('&', r'\&')
\&#
>>> print a.replace('#', r'\#')
&\#
>>> 

你想要使用一个'raw'字符串(用'r'作为替换字符串的前缀),因为raw字符串不会特别对待反斜杠。

其他回答

对于Python 3.8及以上版本,可以使用赋值表达式

[text := text.replace(s, f"\\{s}") for s in "&#" if s in text];

虽然,我不确定这是否被认为是PEP 572中描述的赋值表达式的“适当使用”,但看起来很干净,(在我看来)读起来很好。如果在REPL中运行,末尾的分号会抑制输出。

如果您也想要所有中间字符串,这将是“合适的”。例如,(去掉所有小写元音):

text = "Lorem ipsum dolor sit amet"
intermediates = [text := text.replace(i, "") for i in "aeiou" if i in text]

['Lorem ipsum dolor sit met',
 'Lorm ipsum dolor sit mt',
 'Lorm psum dolor st mt',
 'Lrm psum dlr st mt',
 'Lrm psm dlr st mt']

从好的方面来看,它似乎(出乎意料地?)比公认答案中的一些更快的方法要快,并且似乎在增加字符串长度和增加替换次数的情况下都表现得很好。

下面是用于上述比较的代码。我使用随机字符串来简化我的工作,要替换的字符是从字符串本身随机选择的。(注意:我在这里使用的是ipython的%timeit magic,所以在ipython/jupyter中运行它)。

import random, string

def make_txt(length):
    "makes a random string of a given length"
    return "".join(random.choices(string.printable, k=length))

def get_substring(s, num):
    "gets a substring"
    return "".join(random.choices(s, k=num))

def a(text, replace): # one of the better performing approaches from the accepted answer
    for i in replace:
        if i in text:
             text = text.replace(i, "")

def b(text, replace):
    _ = (text := text.replace(i, "") for i in replace if i in text) 


def compare(strlen, replace_length):
    "use ipython / jupyter for the %timeit functionality"

    times_a, times_b = [], []

    for i in range(*strlen):
        el = make_txt(i)
        et = get_substring(el, replace_length)

        res_a = %timeit -n 1000 -o a(el, et) # ipython magic

        el = make_txt(i)
        et = get_substring(el, replace_length)
        
        res_b = %timeit -n 1000 -o b(el, et) # ipython magic

        times_a.append(res_a.average * 1e6)
        times_b.append(res_b.average * 1e6)
        
    return times_a, times_b

#----run
t2 = compare((2*2, 1000, 50), 2)
t10 = compare((2*10, 1000, 50), 10)

下面是使用str.translate和str.maketrans的python3方法:

s = "abc&def#ghi"
print(s.translate(str.maketrans({'&': '\&', '#': '\#'})))

打印出来的字符串是abc\&def\#ghi。

仅供参考,这对OP没有什么用处,但对其他读者可能有用(请不要投反对票,我知道这一点)。

作为一个有点荒谬但有趣的练习,我想看看是否可以使用python函数式编程来替换多个字符。我很确定这并不比调用replace()两次好。如果性能是个问题,你可以用rust、C、julia、perl、java、javascript甚至awk轻松解决。它使用一个名为pytoolz的外部“助手”包,通过cython加速(cytoolz,它是一个pypi包)。

from cytoolz.functoolz import compose
from cytoolz.itertoolz import chain,sliding_window
from itertools import starmap,imap,ifilter
from operator import itemgetter,contains
text='&hello#hi&yo&'
char_index_iter=compose(partial(imap, itemgetter(0)), partial(ifilter, compose(partial(contains, '#&'), itemgetter(1))), enumerate)
print '\\'.join(imap(text.__getitem__, starmap(slice, sliding_window(2, chain((0,), char_index_iter(text), (len(text),))))))

我甚至不打算解释这一点,因为没有人会使用它来完成多次替换。尽管如此,我还是觉得这样做有点成就感,并认为它可能会激励其他读者,或者赢得一场代码混淆竞赛。

使用在python2.7和python3中可用的reduce。你可以用简洁的python方式替换多个子字符串。

# Lets define a helper method to make it easy to use
def replacer(text, replacements):
    return reduce(
        lambda text, ptuple: text.replace(ptuple[0], ptuple[1]), 
        replacements, text
    )

if __name__ == '__main__':
    uncleaned_str = "abc&def#ghi"
    cleaned_str = replacer(uncleaned_str, [("&","\&"),("#","\#")])
    print(cleaned_str) # "abc\&def\#ghi"

在python2.7中,你不需要导入reduce,但在python3中。你必须从functools模块中导入它。

像这样简单地连接替换函数

strs = "abc&def#ghi"
print strs.replace('&', '\&').replace('#', '\#')
# abc\&def\#ghi

如果替换的数量更多,你可以用这种通用的方法

strs, replacements = "abc&def#ghi", {"&": "\&", "#": "\#"}
print "".join([replacements.get(c, c) for c in strs])
# abc\&def\#ghi