'in-place' строковые модификации в Python
В Python строки неизменяемы.
Какова стандартная идиома для прохождения строки по символу и ее изменения?
Единственными методами, которые я могу придумать, являются некоторые действительно неуклюжие хаки, связанные с объединением с результирующей строкой.
-
В C:
for(int i = 0; i < strlen(s); i++)
{
s[i] = F(s[i]);
}
Это супер выразительно и точно говорит о том, что я делаю. Это то, что я ищу.
Ответы
Ответ 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()