Reputation: 71
Python's behavior seems inconsistent when replacing values in the case shown below (using python 3.6.5)
>>> emptyString = ' '
>>> emptyString.strip().replace('','0') #produces expected results
'0'
>>> notEmptyString = ' 50 '
>>> notEmptyString.strip().replace('','0') #expected '50'
'05000'
>>> shortString = notEmptyString.strip()
>>> shortString #results as expected
'50'
>>> shortString.replace('','0') #unexpected results - expected '50'
'05000'
This is what I'd like to see:
- if string has a value, just strip() the leading and trailing spaces.
- if string is empty (i.e. "") or string is just blank characters (i.e. " ") then strip it to be "" and replace "" with '0'
Example #1... string = " 10 ".... then just strip leading and trailing spaces
Example #2... string = ' ' .... then convert to '0'
I can get the results I want by other means, but I wondered if anybody understands why python produces these results.
Upvotes: 7
Views: 5752
Reputation: 71610
Another way of doing this:
def f(s):
return {'':'0'}.get(s.strip(),s)
print(f(' '))
print(f(' a '))
Output:
0
a
Explanation (for str.replace):
""
is always in a string (to see what i mean 'ab'.count('')
returns 3)Explanation (for my example):
dict.get
for checkingUpvotes: 2
Reputation: 22324
str.replace
worksYou interpret the method str.replace
as if it replaced the whole string by the new value. This is not the case.
What it does is replace every occurence of the first argument by the second argument within the string.
'ababc'.replace('ab', 'x') # 'xxc'
What may be confusing here is that you are replacing every occurence of the empty string. It turns out the empty string is present everywhere, between every two character is an empty string.
If that does not make sense to you just consider that the following is indeed True
'' + '5' + '' + '0' + '' == '50'
So doing this...
s.replace('', '0')
Is equivalent to inserting '0'
between all characters. It is equivalent to the following.
'0'.join(s.split())
What you want to do is strip your string and make it '0'
if it is empty, here are a few ways to do this.
# 1)
s = emptyString.strip()
s = s if s else '0'
# 2)
s = emptyString.strip() or '0'
Upvotes: 3
Reputation: 51039
If s
is a string, then:
s.replace(old, new)
returns a copy of s
with every occurrence of the string old
replaced with new
, so for example:
In [7]: "abracadabra".replace("a","4")
Out[7]: '4br4c4d4br4'
As a special case, if old
is the empty string, it inserts new
at the start and end of the string and between every pairs of characters:
In [8]: "12345678".replace("","_")
Out[8]: '_1_2_3_4_5_6_7_8_'
The rationale is that there's a "empty string" before the first character, between each pair of characters, and after the last character, and that's what's being replaced.
So, replace
isn't doing what you were thinking.
To do what you what, you can use one of the solutions already proposed, or something like this if you're feeling clever:
s.strip() or "0"
Upvotes: 6
Reputation: 273045
This is related to how replace
works.
Think of it as looking through every index of the string, and creating a substring starting from each index. Then it checks if any of the substrings start with the string to look for. It then records the index of the substrings that start with the string to look for, removes the your string to look for, and inserts your replacement string at those indices.
For ''
, there is only one index to look through, and the substring starting from that index is ''
, which starts with ''
, so a 0 is inserted.
For 50
, there are 3 indices to look through. The substrings starting from the indices are:
'50'
'0'
''
All of these substrings start with ''
, so a 0 is inserted in all the indices, creating '05000'
.
Upvotes: 3
Reputation: 13426
As @coldspeed suggested in comment, You need:
def myfunc(string): return string if string.strip() else '0'
print(myfunc(' 050 '))
print(myfunc(' '))
print(myfunc(''))
print(myfunc('abcd'))
Output:
050
0
0
abcd
Upvotes: 2