Kind of like this question, but in reverse.
Given a string like 1, 1/2, or 1 2/3, what’s the best way to convert it into a float? I’m thinking about using regexes on a case-by-case basis, but perhaps someone knows of a better way, or a pre-existing solution. I was hoping I could just use eval, but I think the 3rd case prevents that.
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
maybe something like this (2.6+)
from fractions import Fraction float(sum(Fraction(s) for s in '1 2/3'.split()))
Method 2
I tweaked James’ answer a bit.
def convert_to_float(frac_str):
try:
return float(frac_str)
except ValueError:
num, denom = frac_str.split('/')
try:
leading, num = num.split(' ')
whole = float(leading)
except ValueError:
whole = 0
frac = float(num) / float(denom)
return whole - frac if whole < 0 else whole + frac
print convert_to_float('3') # 3.0
print convert_to_float('3/2') # 1.5
print convert_to_float('1 1/2') # 1.5
print convert_to_float('-1 1/2') # -1.5
Method 3
Though you should stear clear of eval completely. Perhaps some more refined version of:
num,den = s.split( '/' ) wh, num = num.split() result = wh + (float(num)/float(den))
Sorry, meant to be num.split not s.split, and casts. Edited.
Method 4
I see there are already several good answers here, but I’ve had good luck with this. It also has the benefit that it will tolerate non-fraction strings if you’re parsing mixed sets of data, so there’s no need to check if it’s a fraction string or not upfront.
def convert_to_float(frac_str):
try:
return float(frac_str)
except ValueError:
try:
num, denom = frac_str.split('/')
except ValueError:
return None
try:
leading, num = num.split(' ')
except ValueError:
return float(num) / float(denom)
if float(leading) < 0:
sign_mult = -1
else:
sign_mult = 1
return float(leading) + sign_mult * (float(num) / float(denom))
>>> convert_to_float('3')
3.0
>>> convert_to_float('1/4')
0.25
>>> convert_to_float('1 2/3')
1.6666666666666665
>>> convert_to_float('-2/3')
-0.6666666666666666
>>> convert_to_float('-3 1/2')
-3.5
Method 5
That might be a dirty workaround, but you could convert spaces to a + sign to solve the 3rd case (or to a - if your fraction is negative).
Method 6
def fractionToFloat(fraction):
num = 0
mult = 1
if fraction[:1] == "-":
fraction = fraction[1:]
mult = -1
if " " in fraction:
a = fraction.split(" ")
num = float(a[0])
toSplit = a[1]
else:
toSplit = fraction
frac = toSplit.split("/")
num += float(frac[0]) / float(frac[1])
return num * mult
It can also handle “2 1/1e-8”, “-1/3” and “1/5e3”.
Method 7
This implementation avoids using eval and works on pre-2.6 versions of Python.
# matches a string consting of an integer followed by either a divisor
# ("/" and an integer) or some spaces and a simple fraction (two integers
# separated by "/")
FRACTION_REGEX = re.compile(r'^(d+)(?:(?:s+(d+))?/(d+))?$')
def parse(x):
i, n, d = FRACTION_REGEX.match(x).groups()
if d is None: n, d = 0, 1 # if d is None, then n is also None
if n is None: i, n = 0, i
return float(i) + float(n) / float(d)
To test:
>>> for x in ['1', '1/2', '1 2/3']: print(repr(parse(x))) ... 1.0 0.5 1.6666666666666665
Method 8
Depending on what syntax you want to support for your fractions, eval('+'.join(s.split())) (with true division in place — i.e., Python 3 or from __future__ import division in Python 2 — might work. It would cover all the cases you mention, in particular.
Method 9
>>> s="1/2"
>>> eval('/'.join(map(str,map(float,s.split("/")))))
0.5
>>> s="3/5"
>>> eval('/'.join(map(str,map(float,s.split("/")))))
0.59999999999999998
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0