In Python, strings are immutable.
What is the standard idiom to walk through a string character-by-character and modify it?
The only methods I can think of a
Strings are iterable and can be walked through like lists. Strings also have a number of basic methods such as .replace()
that might be what you're looking for. All string methods return a new string. So instead of modifying the string in place you can simply replace its existing value.
>>> mystring = 'robot drama'
>>> mystring = mystring.replace('r', 'g')
>>> mystring
'gobot dgama'
The Python analog of your C:
for(int i = 0; i < strlen(s); i++)
{
s[i] = F(s[i]);
}
would be:
s = "".join(F(c) for c in s)
which is also very expressive. It says exactly what is happening, but in a functional style rather than a procedural style.
def modifyIdx(s, idx, newchar):
return s[:idx] + newchar + s[idx+1:]
you can use the UserString module:
>>> import UserString
... s = UserString.MutableString('Python')
... print s
Python
>>> s[0] = 'c'
>>> print s
cython
Here is an example using translate to switch "-" with "." and uppercase "a"s
>>> from string import maketrans
>>> trans_table = maketrans(".-a","-.A")
>>> "foo-bar.".translate(trans_table)
'foo.bAr-'
This is much more efficient that flipping to byte array and back if you just need to do single char replacements
The question first states that strings are immutable and then asks for a way to change them in place. This is kind of contradictory. Anyway, as this question pops up at the top of the list when you search for "python string in-place modification", I'm adding the answer for a real in place change.
Strings seem to be immutable when you look at the methods of the string class. But no language with an interface to C can really provide immutable data types. The only question is whether you have to write C code in order to achieve the desired modification.
Here python ctypes
is your friend. As it supports getting pointers and includes C-like memory copy functions, a python string can be modified in place like this:
s = 16 * "."
print s
ctypes.memmove(ctypes.c_char_p(s), "Replacement", 11)
print s
Results in:
................
Replacement.....
(Of course, you can calculate the replacement string at runtime by applying a function F
to every character of the original string. Different ways how to do this have been shown in the previous answers.)
Note that I do not in any way encourage doing this. However, I had to write a replacement for a class that was mapped from C++ to python and included a method:
int readData(char* data, int length)
(The caller is supposed to provide memory with length
bytes and the method then writes the available data -- up to length
-- into that memory, returning the number of bytes written.) While this is a perfectly sensible API in C/C++, it should not have been made available as method of a python class or at least the users of the API should be made aware that they may only pass mutable byte arrays as parameter.
As you might expect, "common usage" of the method is as shown in my example (create a string and pass it together with its length as arguments). As I did not really want to write a C/C++ extension I had to come up with a solution for implementing the behavior in my replacement class using python only.