Joe Rytting
Joe Rytting

Reputation: 71

How to replace an empty string with 0, but leave it alone if not empty

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

Answers (5)

U13-Forward
U13-Forward

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

  1. str.replace(..) replaces first arg with second arg
  2. also "" is always in a string (to see what i mean 'ab'.count('') returns 3)

Explanation (for my example):

  1. I create a def (function)
  2. Then i make a dict
  3. Then i do dict.get for checking

Upvotes: 2

Olivier Melançon
Olivier Melançon

Reputation: 22324

How str.replace works

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

How to default an empty string to a value

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

K. A. Buhr
K. A. Buhr

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

Sweeper
Sweeper

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

Sociopath
Sociopath

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

Related Questions