6

I want to find the first float that appears in a string using Python 3.

I looked at other similar questions but I couldn't understand them and when I tried to implement them they didn't work for my case.

An example string would be

I would like 1.5 cookies please

pistache
  • 5,782
  • 1
  • 29
  • 50
Harry Tong
  • 259
  • 1
  • 6
  • 14

4 Answers4

9

I'm pretty sure there's more elegant solution, but this one works for your specific case:

s = 'I would like 1.5 cookies please'

for i in s.split():
    try:
        #trying to convert i to float
        result = float(i)
        #break the loop if i is the first string that's successfully converted
        break
    except:
        continue

print(result) #1.5
Muhammad Dyas Yaskur
  • 6,914
  • 10
  • 48
  • 73
  • Really good answer!! Not requiring `regex` and also recognises negative and non-decimal formatted numbers (+1) – Vinícius Figueiredo Jul 06 '17 at 03:13
  • 3
    This answers the question perfectly, but might be a bit too broad for the user's definition of "float". Try it with `s = "Infinity is better with 3 cookies."` for example :) – pistache Jul 06 '17 at 03:16
  • 1
    @pistache yes, perfect observation, same for [`nan`](https://docs.python.org/3/library/functions.html#float). I found very good answers for the user's question [here](https://stackoverflow.com/questions/4703390/how-to-extract-a-floating-number-from-a-string) and [here](https://stackoverflow.com/questions/385558/extract-float-double-value), they address lots of issues. – Vinícius Figueiredo Jul 06 '17 at 03:41
5

You can find this using regex, notice this pattern will only return the substring if it's already in float type, i.e. decimal fomatting, so something like this:

>>> import re
>>> matches = re.findall("[+-]?\d+\.\d+", "I would like 1.5 cookies please")

As you say you want only the first one:

>>> matches[0]
'1.5'

Edit: Added [+-]? to the pattern for it to recognize negative floats, as pistache recommended!

Vinícius Figueiredo
  • 6,300
  • 3
  • 25
  • 44
1

If you expect whitespace separated decimal floats, using str methods and removing -+.:

s = 'I would like 1.5 cookies please'
results = [t for t in s.split() 
           if t.lstrip('+-').replace('.', '', 1).isdigit()]
print(results[0])  #1.5

lstrip is used to remove the sign only on the lefthand side of the text, and the third argument to replace is used to replace only one dot in the text. The exact implementation depends on the how you expect floats to be formatted (support whitespace between sign, etc).

pistache
  • 5,782
  • 1
  • 29
  • 50
0

I would use a regex. below also checks for negative values.

import re

stringToSearch = 'I would like 1.5 cookies please'
searchPattern = re.compile(".*(-?[0-9]\.[0-9]).*")
searchMatch = searchPattern.search(stringToSearch)

if searchMatch:
    floatValue = searchMatch.group(1)
else:
    raise Exception('float not found')

You can use PyRegex to check the regex.

pistache
  • 5,782
  • 1
  • 29
  • 50
denov
  • 11,180
  • 2
  • 27
  • 43
  • This is very inefficient, why would you include the rest of the string in the search pattern, to then fetch a capture group ? `re.search("\d+\.\d+", s)` works fine, does not copy the whole input string, and is much faster (especially as the input string size grows). – pistache Jul 06 '17 at 03:37