在Python中更改字符串中的一个字符


385

Python中替换字符串中字符的最简单方法是什么?

例如:

text = "abcdefg";
text[1] = "Z";
           ^

Answers:


534

不要修改字符串。

与他们一起工作;仅在需要时才将它们转换为字符串。

>>> s = list("Hello zorld")
>>> s
['H', 'e', 'l', 'l', 'o', ' ', 'z', 'o', 'r', 'l', 'd']
>>> s[6] = 'W'
>>> s
['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd']
>>> "".join(s)
'Hello World'

Python字符串是不可变的(即无法修改)。有很多的原因。除非您别无选择,否则请使用列表,然后将它们变成字符串。


4
那些追求速度/效率的人,请读这篇
AneesAhmed777 '17

4
“不要修改字符串。” 为什么
hacksoi

2
“创建->修改->序列化->分配->免费”比s [6] ='W'更有效?嗯...尽管有很多“原因”,为什么其他语言仍允许呢?有趣的是,如何捍卫一个奇怪的设计(我想是为了爱)。为什么不建议在Python内核中添加直接访问char内存位置的函数MID(strVar,index,newChar),而不是不必要地对整个字符串进行字节改组?
奥斯卡

@ hacksoi,@ oscar,原因很简单:传递指针以实现“按修改进行复制”时不需要引用计数,或者在有人要修改该字符串的情况下完全复制整个字符串-这导致泛型速度提高采用。不需要像MID切片那样的东西:s[:index] + c + s[index+1:]
MultiSkill

1
@oscar用愚蠢的语言,我的意思是除非您明确告诉他们,否则它们不会处理unicode。当然,您可以使用C语言编写具有unicode功能的应用程序。但是您必须时刻关心它,并且需要进行显式测试以避免麻烦。一切都是面向机器的。在学习Python之前,我曾与PHP一起工作过,这种语言简直是一团糟。关于您有关快速CPU的说明,我完全支持您。但是,这个问题的一部分是人们普遍反对过早的优化,因为过早的优化会导致大量的CPU周期泄漏,从而导致解释器和库运行缓慢。
巴萨(Bachsau)

202

最快的方法?

有三种方法。对于速度寻求者,我建议使用“方法2”

方法1

由这个答案给出

text = 'abcdefg'
new = list(text)
new[6] = 'W'
''.join(new)

与“方法2”相比,这相当慢

timeit.timeit("text = 'abcdefg'; s = list(text); s[6] = 'W'; ''.join(s)", number=1000000)
1.0411581993103027

方法2(快速方法)

由这个答案给出

text = 'abcdefg'
text = text[:1] + 'Z' + text[2:]

哪个更快:

timeit.timeit("text = 'abcdefg'; text = text[:1] + 'Z' + text[2:]", number=1000000)
0.34651994705200195

方法3:

字节数组:

timeit.timeit("text = 'abcdefg'; s = bytearray(text); s[1] = 'Z'; str(s)", number=1000000)
1.0387420654296875

1
看看它与bytearray方法的关系也很有趣。
华丽的

1
好建议。字节数组方法也较慢:timeit.timeit("text = 'abcdefg'; s = bytearray(text); s[1] = 'Z'; str(s)", number=1000000)速度是最快的方法的两倍。
Mehdi Nellen'3

2
欣赏测试,这使我重新思考如何处理Python字符串。
光谱

1
真好 请也编辑答案以也包括方法3(字节数组)。
AneesAhmed777 '17

1
应该注意的是,这里的大部分时间都花在了转换...(字符串->字节数组)上。如果您需要对该字符串进行多次编辑,则字节数组方法将更快。
伊恩·苏德贝里


37

Python字符串是不可变的,您可以通过复制来更改它们。
做您想做的最简单的方法可能是:

text = "Z" + text[1:]

text[1:]返回字符串text从位置1到结束,位置从0开始计数,从而“1”是第二个字符。

编辑:您可以对字符串的任何部分使用相同的字符串切片技术

text = text[:1] + "Z" + text[2:]

或者,如果该字母仅出现一次,则可以使用下面建议的搜索和替换技术


我提到了第二个字符,即IE。位置1的字符(与第一个字符0相对应)
kostia

text [0] +“ Z” + text [2:]
wbg

13

从python 2.6和python 3开始,您可以使用可变的字节数组(可以与字符串不同,可以逐个元素地更改):

s = "abcdefg"
b_s = bytearray(s)
b_s[1] = "Z"
s = str(b_s)
print s
aZcdefg

编辑:更改为s

edit2:正如两位炼金术士在评论中所述,此代码不适用于unicode。


这个答案是不正确的。一方面,应该是bytearray(s),而不是bytearray(str)。对于另一个,这将产生:TypeError: string argument without an encoding。如果指定编码,则得到TypeError: an integer is required。这就是Python 3或Python 2的unicode。如果您在Python 2中执行此操作(第二行已更正),它将不适用于非ASCII字符,因为它们可能不仅仅是一个字节。试试看s = 'Héllo',你会得到'He\xa9llo'
两位炼金术士

我在Python 2.7.9上再次尝试了此操作。我无法重新生成您提到的错误(TypeError:不带编码的字符串参数)。
Mahmoud 2015年

该错误仅在使用unicode时适用。尝试s = u'abcdefg'
两位炼金术士

4
不要这样做。此方法忽略了字符串编码的整个概念,这意味着它仅适用于ASCII字符。在当今时代,即使您是英语国家的英语使用者,也无法假定ASCII。Python3最大的后向不兼容(我认为最重要)是修复整个字节=字符串错误的等效性。不要带回来。
亚当

5

就像其他人所说的那样,通常Python字符串应该是不可变的。

但是,如果您使用的是CPython,即python.org的实现,则可以使用ctypes修改内存中的字符串结构。

这是我使用该技术清除字符串的示例。

在python中将数据标记为敏感

为了完整起见,我提到了这一点,这应该是您的最后选择,因为它有点黑。


6
最后一招?如果你曾经这样做,你突然被冠以邪恶!
克里斯·摩根

@ChrisMorgan(如果您的字符串包含密码),用s =''清除它是不够的,因为密码仍然写在内存中的某个位置。通过ctypes清除它是唯一的方法。
卡布

1
@Cabu 在任何情况下我都不会接受这样做的代码。如果您的数据很敏感,并且您在乎这样的安全性,那么这不是适合您的类型。只是不要使用它。使用类似的东西。(更好的是,将其包装在某种东西中,使您或多或少地将其视为不透明的数据,以使您真正无法从中检索到它,以保护您免遭意外。可能有一个用于此的库。不知道。)strbytearraystr
克里斯·摩根

4

此代码不是我的。我不记得我在哪里填写网站表格。有趣的是,您可以使用此字符用一个或多个字符替换一个或多个字符。尽管此回复很晚,但像我这样的新手(随时)可能会觉得有用。

更改文字功能。

mytext = 'Hello Zorld'
mytext = mytext.replace('Z', 'W')
print mytext,

11
这不能回答问题。这根本不是想要的。
克里斯·摩根

2
如果要更换此代码是坏只有第一lmytext = mytext.replace('l', 'W')->HeWWo Zorld
Ooker,2015年

如果您想通过外科手术仅替换1个字符(我是),则完全适合该法案。谢谢!
ProfVersaggi 2015年

@ProfVersaggi绝对是错误的。请参阅上方的Ooker评论。
两位炼金术士2015年

3
@Ooker如果要替换可以使用第一个字符mytext = mytext.replace('l', 'W',1)链接到文档
Alex

2

实际上,使用字符串,您可以执行以下操作:

oldStr = 'Hello World!'    
newStr = ''

for i in oldStr:  
    if 'a' < i < 'z':    
        newStr += chr(ord(i)-32)     
    else:      
        newStr += i
print(newStr)

'HELLO WORLD!'

基本上,我是将“ +”字符串一起添加到新字符串中:)。


4
这将非常慢,因为每个串联都必须产生一个新的字符串对象,因为它们是不可变的,这就是这个问题。
两位炼金术士

0

如果您的世界是100%ascii/utf-8(很多用例都放在该框中):

b = bytearray(s, 'utf-8')
# process - e.g., lowercasing: 
#    b[0] = b[i+1] - 32
s = str(b, 'utf-8')

python 3.7.3


0

我想添加另一种更改字符串中字符的方式。

>>> text = '~~~~~~~~~~~'
>>> text = text[:1] + (text[1:].replace(text[0], '+', 1))
'~+~~~~~~~~~'

与将字符串转换为list并替换ith值然后再次加入相比,速度有多快?

清单方式

>>> timeit.timeit("text = '~~~~~~~~~~~'; s = list(text); s[1] = '+'; ''.join(s)", number=1000000)
0.8268570480013295

我的解决方案

>>> timeit.timeit("text = '~~~~~~~~~~~'; text=text[:1] + (text[1:].replace(text[0], '+', 1))", number=1000000)
0.588400217000526
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.