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

前端 未结 5 631
庸人自扰
庸人自扰 2020-12-01 06:15

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? Bo

相关标签:
5条回答
  • 2020-12-01 06:43

    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[1])
    
        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)
    
    0 讨论(0)
  • 2020-12-01 06:45

    Use strip('%') , as:

    In [9]: "99.5%".strip('%')
    Out[9]: '99.5'               #convert this to float using float() and divide by 100
    
    
    In [10]: def p2f(x):
        return float(x.strip('%'))/100
       ....: 
    
    In [12]: p2f("99%")
    Out[12]: 0.98999999999999999
    
    In [13]: p2f("99.5%")
    Out[13]: 0.995
    
    0 讨论(0)
  • 2020-12-01 07:01

    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
    
    0 讨论(0)
  • 2020-12-01 07:02
    float(stringPercent.strip('%')) / 100.0
    
    0 讨论(0)
  • 2020-12-01 07:03

    Another way: float(stringPercent[:-1]) / 100

    0 讨论(0)
提交回复
热议问题