# What is a clean way to convert a string percent to a float?

Posted on

### Question :

What is a clean way to convert a string percent to a float?

I have looked in the standard library and on StackOverflow, and have not found a similar question. So, is there a way to do the following without rolling my own function? Bonus points if someone writes a beautiful function if there is no built in way.

``````def stringPercentToFloat(stringPercent)
# ???
return floatPercent

p1 = "99%"
p2 = "99.5%"
print stringPercentToFloat(p1)
print stringPercentToFloat(p2)

>>>> 0.99
>>>> 0.995
``````

Use `strip('%')` , as:

``````In : "99.5%".strip('%')
Out: '99.5'               #convert this to float using float() and divide by 100

In : def p2f(x):
return float(x.strip('%'))/100
....:

In : p2f("99%")
Out: 0.98999999999999999

In : p2f("99.5%")
Out: 0.995
``````

``````float(stringPercent.strip('%')) / 100.0
``````

I wrote the following method that should always return the output to the exact same accuracy as the input, with no floating point errors such as in the other answers.

``````def percent_to_float(s):
s = str(float(s.rstrip("%")))
i = s.find(".")
if i == -1:
return int(s) / 100
if s.startswith("-"):
return -percent_to_float(s.lstrip("-"))
s = s.replace(".", "")
i -= 2
if i < 0:
return float("." + "0" * abs(i) + s)
else:
return float(s[:i] + "." + s[i:])
``````

## Explanation

1. Strip the “%” from the end.
2. If percent has no “.”, simply return it divided by 100.
3. If percent is negative, strip the “-” and re-call function, then convert the result back to a negative and return it.
4. Remove the decimal place.
5. Decrement `i` (the index the decimal place was at) by 2, because we want to shift the decimal place 2 spaces to the left.
6. If `i` is negative, then we need to pad with zeros.
• Example: Suppose the input is “1.33%”. To be able to shift the decimal place 2 spaces to the left, we would need to pad with a zero.
7. Convert to a float.

Test case (Try it online):

``````from unittest.case import TestCase

class ParsePercentCase(TestCase):
tests = {
"150%"              : 1.5,
"100%"              : 1,
"99%"               : 0.99,
"99.999%"           : 0.99999,
"99.5%"             : 0.995,
"95%"               : 0.95,
"90%"               : 0.9,
"50%"               : 0.5,
"66.666%"           : 0.66666,
"42%"               : 0.42,
"20.5%"             : 0.205,
"20%"               : 0.2,
"10%"               : 0.1,
"3.141592653589793%": 0.03141592653589793,
"1%"                : 0.01,
"0.1%"              : 0.001,
"0.01%"             : 0.0001,
"0%"                : 0,
}
tests = sorted(tests.items(), key=lambda x: -x)

def test_parse_percent(self):
for percent_str, expected in self.tests:
parsed = percent_to_float(percent_str)
self.assertEqual(expected, parsed, percent_str)

def test_parse_percent_negative(self):
negative_tests = [("-" + s, -f) for s, f in self.tests]
for percent_str, expected in negative_tests:
parsed = percent_to_float(percent_str)
self.assertEqual(expected, parsed, percent_str)
``````

`float(stringPercent[:-1]) / 100`
Based on the answer from @WKPlus this solution takes into account the locales where the decimal point is either a point `.` or a comma `,`
``````float("-3,5%".replace(',','.')[:-1]) / 100