Подтвердить что ты не робот

'in-place' строковые модификации в Python

В Python строки неизменяемы.

Какова стандартная идиома для прохождения строки по символу и ее изменения?

Единственными методами, которые я могу придумать, являются некоторые действительно неуклюжие хаки, связанные с объединением с результирующей строкой.

-

В C:

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

Это супер выразительно и точно говорит о том, что я делаю. Это то, что я ищу.

4b9b3361

Ответ 1

Не используйте строку, используйте что-то изменяемое, например 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

Edit:

Так как это bytearray, вы не (обязательно) работаете с символами. Вы работаете с байтами. Так что это тоже работает:

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 напрямую.

Ответ 2

Аналог Python вашего C:

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

:

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

что также очень выразительно. Он точно говорит о том, что происходит, но в функциональном стиле, а не в процедурном стиле.

Ответ 3

вы можете использовать модуль UserString:

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

Ответ 4

Я бы сказал, что самый Pythonic способ использовать map():

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

Это эквивалент записи:

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

Ответ 5

string.translate, вероятно, является самой близкой функцией того, что вам нужно.

Ответ 6

Строки повторяются и могут проходить через списки. Строки также имеют ряд основных методов, таких как .replace(), которые могут быть тем, что вы ищете. Все методы string возвращают новую строку. Поэтому вместо того, чтобы изменять строку на месте, вы можете просто заменить ее существующее значение.

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

Ответ 7

Назначение определенного символа конкретному индексу в строке не является особенно распространенной операцией, поэтому, если вам нужно это сделать, подумайте о том, может ли быть лучший способ выполнить задачу. Но если вам это нужно, возможно, наиболее стандартным способом было бы преобразовать строку в список, внести изменения и затем преобразовать ее в строку.

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

EDIT: Как указано в ответе bstpierre, bytearray, вероятно, даже лучше для этой задачи, чем list, если вы не работаете с строками Unicode.

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

Ответ 8

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

Если вы хотите сохранить эту новую строку, вам нужно будет mystring = mystring.replace("1", "i"). Это связано с тем, что в Python строки неизменяемы.

Ответ 9

Вот пример использования перевода для переключения "-" на ".". и в верхнем регистре "a" s

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

Это намного эффективнее, чем переключение на байтовый массив и обратно, если вам просто нужно выполнить отдельные замены char

Ответ 10

Сначала вопрос гласит, что строки являются неизменяемыми, а затем запрашивает способ их изменения на месте. Это довольно противоречиво. В любом случае, поскольку этот вопрос всплывает в верхней части списка, когда вы ищете "изменение строки Python на месте", я добавляю ответ для реального изменения на месте.

Строки кажутся неизменными, когда вы смотрите на методы класса string. Но ни один язык с интерфейсом для C не может обеспечить неизменные типы данных. Вопрос только в том, нужно ли вам писать код на C, чтобы добиться желаемой модификации.

Здесь питон 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 - в эту память, возвращая количество записанных байтов.) Хотя это совершенно разумный API в C/C++, он не должен быть доступен как метод класса python, или, по крайней мере, пользователи API должны знать, что они могут передавать только изменяемые байтовые массивы в качестве параметра.

Как и следовало ожидать, "общее использование" метода такое, как показано в моем примере (создайте строку и передайте ее вместе с длиной в качестве аргументов). Поскольку я действительно не хотел писать расширение C/C++, мне пришлось придумать решение для реализации поведения в моем классе замещения с использованием только Python.

Ответ 11

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

Ответ 12

Если мне когда-нибудь понадобится сделать что-то подобное, я просто преобразую его в изменяемый список

Например... (хотя было бы проще использовать сортировку (см. второй пример))

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

Ответ 13

Вы можете использовать класс StringIO для получения файлово-изменяемого интерфейса строки.

Ответ 14

Я сделал это так:

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()