Reputation: 282885
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.
Upvotes: 41
Views: 45225
Reputation: 708
Though you should steer clear of eval completely. Perhaps some more refined version of:
num, den = s.split('/')
wh, num = num.split()
result = wh + float(num)/float(den)
Upvotes: 8
Reputation: 122439
maybe something like this (2.6+)
from fractions import Fraction
float(sum(Fraction(s) for s in '1 2/3'.split()))
If you must handle negative values, too, you could use:
fraction_string = '-1 2/3'
negative = 1
if fraction_string.startswith('-'):
fraction_string = fraction_string[1:]
negative = -1
result = negative*float(sum(Fraction(s) for s in fraction_string.split()))
Upvotes: 58
Reputation: 143154
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
Upvotes: 2
Reputation: 282885
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
Upvotes: 18
Reputation: 6236
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
Upvotes: 4
Reputation: 3371
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".
Upvotes: 2
Reputation: 342373
>>> 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
Upvotes: -1
Reputation: 881695
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.
Upvotes: 1
Reputation: 49719
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).
Upvotes: 2