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

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

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

当前回答

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

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

其他回答

对于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)

这将帮助人们找到一个简单的解决方案。

def replacemany(our_str, to_be_replaced:tuple, replace_with:str):
    for nextchar in to_be_replaced:
        our_str = our_str.replace(nextchar, replace_with)
    return our_str

os = 'the rain in spain falls mainly on the plain ttttttttt sssssssssss nnnnnnnnnn'
tbr = ('a','t','s','n')
rw = ''

print(replacemany(os,tbr,rw))

输出:

他是我的家人他的pli

也许是一个简单的循环字符替换:

a = '&#'

to_replace = ['&', '#']

for char in to_replace:
    a = a.replace(char, "\\"+char)

print(a)

>>> \&\#

仅供参考,这对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),))))))

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

使用正则表达式的高级方式

import re
text = "hello ,world!"
replaces = {"hello": "hi", "world":" 2020", "!":"."}
regex = re.sub("|".join(replaces.keys()), lambda match: replaces[match.string[match.start():match.end()]], text)
print(regex)