Replacing one character of a string in python - python

In python, are strings mutable? The line someString[3] = "a" throws the error
TypeError: 'str' object does not
support item assignment
I can see why (as I could have written someString[3] = "test" and that would obviously be illegal) but is there a method to do this in python?

Python strings are immutable, which means that they do not support item or slice assignment. You'll have to build a new string using i.e. someString[:3] + 'a' + someString[4:] or some other suitable approach.

Instead of storing your value as a string, you could use a list of characters:
>>> l = list('foobar')
>>> l[3] = 'f'
>>> l[5] = 'n'
Then if you want to convert it back to a string to display it, use this:
>>> ''.join(l)
'foofan'
If you are changing a lot of characters one at a time, this method will be considerably faster than building a new string each time you change a character.

In new enough pythons you can also use the builtin bytearray type, which is mutable. See the stdlib documentation. But "new enough" here means 2.6 or up, so that's not necessarily an option.
In older pythons you have to create a fresh str as mentioned above, since those are immutable. That's usually the most readable approach, but sometimes using a different kind of mutable sequence (like a list of characters, or possibly an array.array) makes sense. array.array is a bit clunky though, and usually avoided.

>>> import ctypes
>>> s = "1234567890"
>>> mutable = ctypes.create_string_buffer(s)
>>> mutable[3] = "a"
>>> print mutable.value
123a567890

Use this:
someString.replace(str(list(someString)[3]),"a")

Just define a new string equaling to what you want to do with your current string.
a = str.replace(str[n],"")
return a

Related

String addresses [duplicate]

This question already has answers here:
Does Python do slice-by-reference on strings?
(2 answers)
Closed 2 years ago.
While going through the mutable and immutable topic in depth. I found that the variable address is different when you simply call "s" v/s when you call it by index. Why is this so?
s = "hello!"
print(id(s))
print(id(s[0:5]))
s[0:5] creates a new, temporary string. That, of course, has a different ID. One "normal" case would be to assign this expression to a variable; the separate object is ready for that assignment.
Also note that a common way to copy a sequence is with a whole-sequence slice, such as
s_copy = s[:]
It's creating a new string, as Python strings are immutable (cannot be changed once created)
However, many implementations of Python will tag the same object if they find they're creating the same string, which makes for a good example. Here's what happens in a CPython 3.9.1 shell (which I suspect is one of the most common at time of writing)
>>> s = "hello!"
>>> print(id(s))
4512419376
>>> print(id(s[0:5])) # new string from slice of original
4511329712
>>> print(id(s[0:5])) # refers to the newly-created string
4511329712
>>> print(id(s[0:6])) # references original string
4512419376
>>> print(id(s[:])) # trivial slice also refers to original
4512419376
In general you should not rely on this behavior and only consider it an example.
Check for string equality with ==!
See also Why does comparing strings using either '==' or 'is' sometimes produce a different result?
Strings are immutable and thus by creating a new substring by slicing, the new String has a new address in memory. Because the old String cannot be altered due to it being immutable.

Converting python string into bytes directly without eval()

eval() seems to be dangerous to use when processing unknown strings, which is what a part of my project is doing.
For my project I have a string, called:
stringAsByte = "b'a'"
I've tried to do the following to convert that string directly (without using eval):
byteRepresentation = str.encode(stringAsByte)
print(byteRepresentation) # prints b"b'a'"
Clearly, that didn't work, so instead of doing:
byteRepresentation = eval(stringAsByte) # Uses eval!
print(byteRepresentation) # prints b'a'
Is there another way where I can get the output b'a'?
yes, with ast.literal_eval which is safe since it only evaluates literals.
>>> import ast
>>> stringAsByte = "b'a'"
>>> ast.literal_eval(stringAsByte)
b'a'

Python insert a line break in a string after character "X"

What is the python syntax to insert a line break after every occurrence of character "X" ? This below gave me a list object which has no split attribute error
for myItem in myList.split('X'):
myString = myString.join(myItem.replace('X','X\n'))
myString = '1X2X3X'
print (myString.replace ('X', 'X\n'))
You can simply replace X by "X\n"
myString.replace("X","X\n")
Python 3.X
myString.translate({ord('X'):'X\n'})
translate() allows a dict, so, you can replace more than one different character at time.
Why translate() over replace() ? Check translate vs replace
Python 2.7
myString.maketrans('X','X\n')
A list has no split method (as the error says).
Assuming myList is a list of strings and you want to replace 'X' with 'X\n' in each once of them, you can use list comprehension:
new_list = [string.replace('X', 'X\n') for string in myList]
Based on your question details, it sounds like the most suitable is str.replace, as suggested by #DeepSpace. #levi's answer is also applicable, but could be a bit of a too big cannon to use.
I add to those an even more powerful tool - regex, which is slower and harder to grasp, but in case this is not really "X" -> "X\n" substitution you actually try to do, but something more complex, you should consider:
import re
result_string = re.sub("X", "X\n", original_string)
For more details: https://docs.python.org/2/library/re.html#re.sub

python: how to generate char by adding int

I can use 'a'+1 to get 'b' in C language, so what the convient way to do this in Python?
I can write it like:
chr(ord('a')+1)
but I don't know whether it is the best way.
Yes, this is the best way. Python doesn't automatically convert between a character and an int the way C and C++ do.
Python doesn't actually have a character type, unlike C, so yea, chr(ord is the way to do it.
If you wanted to do it a bit more cleanly, you could do something like:
def add(c, x):
return chr(ord(c)+x)
There is the bytearray type in Python -
it is slower than regular strings, but behaves mostly like a C string:
it is mutable, acessing inidividual elements raise 0 - 255 integer numbers, insetead of substrings with lenght 1, and you can assign to the elements. Still, it is represented as a string, and in Python 2, can be used in most places a string can without being cast to a str object:
>>> text = bytearray("a")
>>> text
bytearray(b'a')
>>> print text
a
>>> text[0]+=1
>>> print text
b
>>> text[0]
98
>>> print "other_text" + text
other_textb
When using Python 3, to use the contents of a bytearray as a text object, simply call its decode method with an appropriate encoding such as "latin1" or utf-8":
>>> print ("other_text" + text.decode("latin1"))
What you're doing is really the right way. Python does not conflate a character with its numerical codepoint, as C and similar languages do. The reason is that once you go beyond ASCII, the same integral value can represent different characters, depending on the encoding. C emphasizes direct access to the underlying hardware formats, but python emphasizes well-defined semantics.

Python Remove last char from string and return it

While I know that there is the possibility:
>>> a = "abc"
>>> result = a[-1]
>>> a = a[:-1]
Now I also know that strings are immutable and therefore something like this:
>>> a.pop()
c
is not possible.
But is this really the preferred way?
Strings are "immutable" for good reason: It really saves a lot of headaches, more often than you'd think. It also allows python to be very smart about optimizing their use. If you want to process your string in increments, you can pull out part of it with split() or separate it into two parts using indices:
a = "abc"
a, result = a[:-1], a[-1]
This shows that you're splitting your string in two. If you'll be examining every byte of the string, you can iterate over it (in reverse, if you wish):
for result in reversed(a):
...
I should add this seems a little contrived: Your string is more likely to have some separator, and then you'll use split:
ans = "foo,blah,etc."
for a in ans.split(","):
...
Not only is it the preferred way, it's the only reasonable way. Because strings are immutable, in order to "remove" a char from a string you have to create a new string whenever you want a different string value.
You may be wondering why strings are immutable, given that you have to make a whole new string every time you change a character. After all, C strings are just arrays of characters and are thus mutable, and some languages that support strings more cleanly than C allow mutable strings as well. There are two reasons to have immutable strings: security/safety and performance.
Security is probably the most important reason for strings to be immutable. When strings are immutable, you can't pass a string into some library and then have that string change from under your feet when you don't expect it. You may wonder which library would change string parameters, but if you're shipping code to clients you can't control their versions of the standard library, and malicious clients may change out their standard libraries in order to break your program and find out more about its internals. Immutable objects are also easier to reason about, which is really important when you try to prove that your system is secure against particular threats. This ease of reasoning is especially important for thread safety, since immutable objects are automatically thread-safe.
Performance is surprisingly often better for immutable strings. Whenever you take a slice of a string, the Python runtime only places a view over the original string, so there is no new string allocation. Since strings are immutable, you get copy semantics without actually copying, which is a real performance win.
Eric Lippert explains more about the rationale behind immutable of strings (in C#, not Python) here.
The precise wording of the question makes me think it's impossible.
return to me means you have a function, which you have passed a string as a parameter.
You cannot change this parameter. Assigning to it will only change the value of the parameter within the function, not the passed in string. E.g.
>>> def removeAndReturnLastCharacter(a):
c = a[-1]
a = a[:-1]
return c
>>> b = "Hello, Gaukler!"
>>> removeAndReturnLastCharacter(b)
!
>>> b # b has not been changed
Hello, Gaukler!
Yes, python strings are immutable and any modification will result in creating a new string. This is how it's mostly done.
So, go ahead with it.
I decided to go with a for loop and just avoid the item in question, is it an acceptable alternative?
new = ''
for item in str:
if item == str[n]:
continue
else:
new += item

Categories

Resources