如何替换字符串末尾的某些字符?

50

我想在Python字符串的末尾替换字符。我有这个字符串:

s = "123123"

我想把最后一个2替换成x。假设有一个名为replace_last的方法:

>>> replace_last(s, '2', 'x')
'1231x3'

有没有内置的或简单的方法来做到这一点?


这类似于Python的 str.replace()

>>> s.replace('2', 'x', 1)
'1x3123'

但是它是从末尾到开头的。

10个回答

56

使用正则表达式函数re.sub替换字符串结尾的单词

import re
s = "123123"
s = re.sub('23$', 'penguins', s)
print s

输出:

1231penguins
或者
import re
s = "123123"
s = re.sub('^12', 'penguins', s)
print s

输出:

penguins3123

对于问题中给出的示例:r = re.sub(r"2[^2]$", "x", s) - Eric
1
问题并不是关于字符串的结尾,而是关于从字符串末尾进行替换。 - Mina
@Eric 那个删除了最后3个。用这个:re.sub(r"2([^2])$", r"x\1", s)。虽然无论如何,由于字符类别的原因,这对于多字符替换都不起作用。 - wjandrea

45

这正是 rpartition 函数的用途:

S.rpartition(sep) -> (head, sep, tail)

从字符串 S 的末尾开始查找分隔符 sep,返回它之前的部分、分隔符本身和它之后的部分。如果找不到分隔符,则返回两个空字符串和原字符串 S

我编写了该函数以展示如何在您的用例中使用 rpartition

def replace_last(source_string, replace_what, replace_with):
    head, _sep, tail = source_string.rpartition(replace_what)
    return head + replace_with + tail

s = "123123"
r = replace_last(s, '2', 'x')
print r

输出:

1231x3

2
这个解决方案有缺陷。如果未找到replace_what字符串,则replace_with将被插入到字符串的开头。 - Jean-Marc S.

17
这是为数不多没有左右版本的字符串函数之一,但我们可以使用一些具有此功能的字符串函数来模拟其行为。
>>> s = '123123'
>>> t = s.rsplit('2', 1)
>>> u = 'x'.join(t)
>>> u
'1231x3'

或者

>>> 'x'.join('123123'.rsplit('2', 1))
'1231x3'

4
与已接受的解决方案相比,这个解决方案更短,并且具有一个优点,就是只需更改 rsplit() 函数中第二个参数的值就可以从右侧进行多次替换。对我来说,这是一个优点,因为我在寻找解决此问题的方法时不必使用循环进行多次替换。 - Simon
我能想到的唯一问题是,如果你传递了 sep=None 并且 s 包含多个空格字符,则它不会像替换一样运行。例如:s = "1\n\n1",我们有 s.rsplit(None, 1) == ['1', '1'] 而不是 s.rsplit('\n', 1) == ['1\n', '1'] - wjandrea

8
>>> s = "aaa bbb aaa bbb"
>>> s[::-1].replace('bbb','xxx',1)[::-1]
'aaa bbb aaa xxx'

针对你的第二个例子:
>>> s = "123123"
>>> s[::-1].replace('2','x',1)[::-1]
'1231x3'

2
这仅适用于回文,修复方法:source[::-1].replace(old[::-1], new[::-1], count)[::-1] - Kresimir
@Kresimir -- 感谢你发现并修复了回文问题。双手赞!(个人认为这个 [::-1] 方法最好,因为可以使用replace()正常语法进行正向和反向替换)。 - Daniel Goldfarb

5
当所需匹配项在字符串末尾时,re.sub可提供帮助。
>>> import re
>>> s = "aaa bbb aaa bbb"
>>> s
'aaa bbb aaa bbb'
>>> re.sub('bbb$', 'xxx', s)
'aaa bbb aaa xxx'
>>> 

2
这里提供一种基于您问题的简单解决方案。如果需要更好的答案,需要更多的信息。
>>> s = "aaa bbb aaa bbb"
>>> separator = " "
>>> parts = s.split(separator)
>>> separator.join(parts[:-1] + ["xxx"])
'aaa bbb aaa xxx'

更新

(在看到修改后的问题之后) 这是另一个非常具体的答案。

>>> s = "123123"
>>> separator = "2"
>>> parts = s.split(separator)
>>> separator.join(parts[:-1]) + "x" + parts[-1]
'1231x3'

更新2

有更好的方法来完成这个操作。感谢@mizipzor


更新存在与Mizipzor的回答相同的问题:如果未找到“separator”,则替换将插入字符串的开头。 - wjandrea

1

有一种方法可以处理replace,使其向后工作。

思路是使用[::-1]反转字符串、要替换的文本和新文本。逻辑保持不变。

例如:

>>> a = "123 456 123 456 123 456"

我们希望用"abc"替换最后一个(或两个,或n个)出现的"123"

>>> a[::-1].replace("123"[::-1], "abc"[::-1], 1)[::-1]
'123 456 123 456 abc 456'

这可以作为一个行为与replace完全相同的函数来实现。
def replace_right(text, old, new, count=-1):
    """
    Return a copy of text with all occurrences of substring old
    replaced by new, starting from the right.

    If count is given and is not -1, only the first count
    occurrences are replaced.
    """
    return text[::-1].replace(old[::-1], new[::-1], count)[::-1]

执行:

>>> replace_right(a, "123", "abc", 1)
'123 456 123 456 abc 456'

>>> replace_right(a, "123", "abc", 2)
'123 456 abc 456 abc 456'

0

有一种非常简单的方法来做到这一点,跟随我的步骤

s = "stay am stay am  delete am"
#  want to remove the last am
s = s[:s.rfind('am')]
print(s)

首先,我们找到am的最后一次出现的索引号,然后取0号索引到该特定索引。


1
谢谢,但这不是关于“删除”,而是“替换”。 - Freewind
嗨@Freewind 删除后,您可以在该位置连接任何字符串代码 str =“stay am stay am delete vvamvv gggg” #想要删除最后一个am str = str [: str.rfind('am')] +“REPLACED”+ str [(str.rfind('am')+ len(“am”):] print(str) - Oishik Sinha
str是一个糟糕的变量名,因为它遮蔽了Python内置的str类型。最好使用更具描述性的名称,或者至少像s这样的名称。我已经为您修复了它 :) 参见TypeError: 'list' object is not callable - wjandrea

0

我得到了一个巧妙的答案,但效率不够高

fname = '12345.png.pngasdfg.png'
suffix = '.png'
fname_rev = fname[::-1]
suffix_rev = suffix[::-1]
fullname_rev = fname_rev.replace(suffix_rev, '', 1)
fullname = fullname_rev[::-1]
fullname '12345.png.pngasdfg'

内置函数 replace() 接受三个参数 str.replace(old, new, max_time) 因此您可以从原始字符串中删除最后匹配的字符串。

您还需要反转 new 参数。请参考 Taha 的回答 进行完整实现。 - wjandrea
你为什么说它“不够高效”?在CPython中,字符串方法是用C实现的,所以它们应该非常快。只有非常大的字符串才会有显著影响,不是吗? - wjandrea

-1
对于第二个例子,我建议使用rsplit,因为它非常简单易用且直接实现了目标。以下是一个使用它的小函数:
def replace_ending(sentence, old, new):
    if sentence.endswith(old):
        i = sentence.rsplit(old,1)
        new_sentence =new.join(i)
        return new_sentence
    return sentence

print(replace_ending("aaa bbb aaa bbb", "bbb", "xxx")) 

输出:

aaa bbb aaa xxx


这是否比Chris Adams的答案更有用?我不确定为什么你要使用sentence.endswith(),因为问题中的示例并没有以要替换的子字符串结尾。 - wjandrea

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接