Python中的“就地”字符串修改

时间:2010-08-11 23:52:58

标签: python string

在Python中,字符串是不可变的。

逐个字符地逐字逐句地修改它是什么标准习惯用法?

我能想到的唯一方法是与加入结果字符串相关的一些真正棘手的黑客。

-

在C:

for(int i = 0; i < strlen(s); i++)
{
   s[i] = F(s[i]);
}

这是 super 表达,并准确地说出我在做什么。这就是我要找的。

14 个答案:

答案 0 :(得分:17)

不要使用字符串,使用像bytearray这样可变的东西:

#!/usr/bin/python

s = bytearray("my dog has fleas")
for n in xrange(len(s)):
    s[n] = chr(s[n]).upper()
print s

结果:

MY DOG HAS FLEAS

编辑:

由于这是bytearray,因此您不一定(必须)使用字符。您正在使用 bytes 。所以这也有效:

s = bytearray("\x81\x82\x83")
for n in xrange(len(s)):
    s[n] = s[n] + 1
print repr(s)

给出:

bytearray(b'\x82\x83\x84')

如果要修改Unicode字符串中的字符,您可能希望使用memoryview,尽管它不直接支持Unicode。

答案 1 :(得分:16)

C的Python模拟:

for(int i = 0; i < strlen(s); i++)
{
   s[i] = F(s[i]);
}

将是:

s = "".join(F(c) for c in s)

也很富有表现力。它准确地说明了正在发生的事情,但是以功能性风格而不是程序风格。

答案 2 :(得分:10)

您可以使用UserString模块:

 >>> import UserString
... s = UserString.MutableString('Python')
... print s
Python
>>> s[0] = 'c'
>>> print s
cython

答案 3 :(得分:7)

我说最Pythonic的方法是使用map()

s = map(func, s) # func has been applied to every character in s

这相当于写作:

s = "".join(func(c) for c in s)

答案 4 :(得分:3)

string.translate可能是你所追求的最接近的功能。

答案 5 :(得分:2)

字符串是可迭代的,可以像列表那样遍历。字符串还有许多基本方法,例如.replace()可能正是您正在寻找的方法。所有字符串方法都返回一个新字符串因此,您可以简单地替换其现有值,而不是修改字符串。

>>> mystring = 'robot drama'
>>> mystring = mystring.replace('r', 'g')
>>> mystring
'gobot dgama'

答案 6 :(得分:2)

将特定字符分配给字符串中的特定索引并不是特别常见的操作,因此如果您发现自己需要这样做,请考虑是否有更好的方法来完成任务。但是如果你确实需要,可能最标准的方法是将字符串转换为列表,进行修改,然后将其转换回字符串。

s = 'abcdefgh'
l = list(s)
l[3] = 'r'
s2 = ''.join(l)

编辑:正如bstpierre的回答一样,bytearray对于此任务可能比list更好,只要您不使用Unicode字符串。< / p>

s = 'abcdefgh'
b = bytearray(s)
b[3] = 'r'
s2 = str(b)

答案 7 :(得分:1)

>>> mystring = "Th1s 1s my str1ng"
>>> mystring.replace("1", "i")
'This is my string'

如果您要存储此字符串,则必须mystring = mystring.replace("1", "i")。这是因为在Python中字符串是不可变的。

答案 8 :(得分:1)

以下是使用translate切换“ - ”和“。”的示例。和大写的“a”s

>>> from string import maketrans
>>> trans_table = maketrans(".-a","-.A")
>>> "foo-bar.".translate(trans_table)
'foo.bAr-'

如果你只需要进行单个char替换,那么翻转到字节数组并返回它会更有效

答案 9 :(得分:1)

该问题首先指出字符串是不可变的,然后要求一种更改其位置的方法。这有点矛盾。无论如何,当您搜索“ python字符串就地修改”时,此问题在列表的顶部弹出,因此我添加了真正就地更改的答案。

当您查看字符串类的方法时,字符串似乎是不可变的。但是,没有任何具有C接口的语言能够真正提供不可变的数据类型。唯一的问题是,是否必须编写C代码才能实现所需的修改。

在这里python ctypes是您的朋友。由于它支持获取指针并包括类似C的内存复制功能,因此可以如下修改python字符串

s = 16 * "."
print s
ctypes.memmove(ctypes.c_char_p(s), "Replacement", 11)
print s

结果:

................
Replacement.....

(当然,您可以在运行时通过将函数F应用于原始字符串的每个字符来计算替换字符串。前面的答案中已经显示了执行此操作的不同方法。)

请注意,我绝不鼓励这样做。但是,我必须编写一个替换类,该类从C ++映射到python,并包含一个方法:

int readData(char* data, int length)

(调用者应该为内存提供length字节,然后该方法将可用数据(最多length)写入该内存,并返回写入的字节数。)这是在C / C ++中非常明智的API,不应将其作为python类的方法使用,或者至少应使API的用户知道他们只能传递可变字节数组作为参数。

如您所料,该方法的“常用用法”如我的示例所示(创建一个字符串并将其长度与长度一起作为参数传递)。因为我真的不想编写C / C ++扩展,所以我不得不想出一个解决方案,仅使用python在替换类中实现该行为。

答案 10 :(得分:0)

def modifyIdx(s, idx, newchar):
    return s[:idx] + newchar + s[idx+1:]

答案 11 :(得分:0)

如果我需要做类似的事情,我只需将其转换为可变列表

例如......(尽管使用sort会更容易(参见第二个例子))

>>> s = "abcdfe"
>>> s = list(s)
>>> s[4] = "e"
>>> s[5] = "f"
>>> s = ''.join(s)
>>> print s
abcdef
>>>
# second example
>>> s.sort()
>>> s = ''.join(s)

答案 12 :(得分:0)

您可以使用StringIO类来接收字符串的类似文件的可变接口。

答案 13 :(得分:0)

我这样做是这样的:

import tempfile
import shutil

...

f_old = open(input_file, 'r')
with tempfile.NamedTemporaryFile() as tmp:
    for line in f_old:
        tmp.write(line.replace(old_string, new_string))
    f_old.close()
    tmp.flush()
    os.fsync(tmp)
    shutil.copy2(tmp.name, input_file)
    tmp.close()