convert an alphanumeric string into a numeric one [duplicate] - python

This question already has answers here:
Python equivalent to atoi / atof
(7 answers)
Closed 9 years ago.
I looked around and I do not see a clear answer for Python to convert an alphanumeric string to a numeric one. Here is an example of numbers I would like to convert.
"1234alpha" --> 1234
"a1234asdf" --> 0
"1234.56yt" --> 1234.56
Any advice would be appreciated.
DK

For a change itertools and no regex:
>>> import itertools as it
>>> number = ''.join(it.takewhile(str.isdigit, '123dfd'))
>>> int(number) if number else 0
123
>>> number = ''.join(it.takewhile(str.isdigit, 'a123dfd'))
int(number) if number else 0
0
Somewhat uglier it works for floats:
>>> number = ''.join(it.takewhile(lambda x: x.isdigit() or
x == '.', '123.45dfd'))
>>> float(number) if number else 0
123.45
Floats, negatives:
def make_number(alphanum):
sign = 1
if alphanum and alphanum[0] in '+-':
sign = int(alphanum[0] + '1')
alphanum = alphanum[1:]
try:
return float(''.join(it.takewhile(lambda x: x.isdigit()
or x == '.', alphanum))) * sign
except ValueError:
return 0
Conclusion: Changing the requirements along the way can turn a simple solution into a complicated one.

To support positive/negative integer/float numbers, you could use a slightly modified regexp from Extract float/double value:
import re
re_float = re.compile("""(?x)
^
[+-]?\ * # first, match an optional sign *and space*
( # then match integers or f.p. mantissas:
\d+ # start out with a ...
(
\.\d* # mantissa of the form a.b or a.
)? # ? takes care of integers of the form a
|\.\d+ # mantissa of the form .b
)
([eE][+-]?\d+)? # finally, optionally match an exponent
""")
def extract_number(s, default=None):
m = re_float.match(s)
if not m:
return default # no number found
f = float(m.group(0)) #XXX to support huge numbers, try/except int() first
return int(f) if f.is_integer() else f
Example
for s in sys.stdin:
print(extract_number(s, default=0))
Input
1234alpha
a1234asdf
1234.56yt
-1e20.
Output
1234
0
1234.56
-100000000000000000000

You can use the re module:
import re
def alp(s):
m = re.match('\d+', s)
return int(m.group(0)) if m is not None and m.start() == 0 else 0
In [3]: alp('a1234asdf')
Out[3]: 0
In [4]: alp('1234alpha')
Out[4]: 1234
If you want to include negative integers:
def alp_neg(s):
m = re.match('[+-]?\d+', s)
return int(m.group(0)) if m is not None and m.start() == 0 else 0
If you want floats too:
def alp_floats(s):
m = re.match('[+-]?\d+(\.\d+)?', s)
return float(m.group(0)) if m is not None and m.start() == 0 else 0
In [7]: alp_floats('-12.2ss31.232sadas')
Out[7]: -12.2

import re
def str_to_int(string):
match = re.match("\d+", string)
if match:
try:
return int(match.group())
except ValueError:
return float(match.group())
else:
return 0
str_to_int("1234alpha")
1234
str_to_int("a1234asdf")
0

import ast
from itertools import takewhile
ast.literal_eval(''.join(takewhile(lambda x: x<='9', string)) or '0')

When the rules for what is OK become hard to define, you might consider this binary search approach that tries to find the bound.
def binsearch_prefix(seq, predicate):
best_upper = 0
lower, upper = 0, len(seq)
while lower < upper:
mid = (lower + upper) / 2
if predicate(seq[:mid]):
best_upper = mid
lower = mid + 1
else:
upper = mid
return seq[:best_upper]
It will return the part of the string that you consider acceptable. For example, this could be your accept function:
def can_float(s):
try:
float(s)
return True
except ValueError:
return False
Example:
print binsearch_prefix(can_float, "1234alpha") # "1234"
print binsearch_prefix(can_float, "a1234asdf") # ""
print binsearch_prefix(can_float, "1234.56yt") # "1234.56"
You may then format the prefix any way you like.

Maybe use regular expressions?
import re
def str2num(s):
try:
num = re.match(r'^([0-9]+)', s).group(1)
except AttributeError:
num = 0
return int(num)
print str2num('1234alpha')
print str2num('a1234asdf')
Output:
1234
0

Related

sequential counting using letters instead of numbers [duplicate]

This question already has answers here:
How to count sequentially using letters instead of numbers?
(3 answers)
Closed 2 months ago.
I need a method that 'increments' the string a to z and than aa to az and then ba to bz and so on, like the columns in an excel sheet. I will feed the method the previous string and it should increment to the next letter.
PSEUDO CODE
def get_next_letter(last_letter):
return last_letter += 1
So I could use it like so:
>>> get_next_letter('a')
'b'
>>> get_next_letter('b')
'c'
>>> get_next_letter('c')
'd'
...
>>> get_next_letter('z')
'aa'
>>> get_next_letter('aa')
'ab'
>>> get_next_letter('ab')
'ac'
...
>>> get_next_letter('az')
'ba'
>>> get_next_letter('ba')
'bb'
...
>>> get_next_letter('zz')
'aaa'
I believe there are better ways to handle this, but you can implement the algorithm for adding two numbers on paper...
def get_next_letter(string):
x = list(map(ord, string)) # convert to list of numbers
x[-1] += 1 # increment last element
result = ''
carry = 0;
for c in reversed(x):
result = chr((c + carry )) + result # i'm not accounting for when 'z' overflows here
carry = c > ord('z')
if carry: # add the new letter at the beggining in case there is still carry
result = 'a' + result
return result.replace('{', 'a') # replace overflowed 'z' with 'a'
all proposed are just way too complicated
I came up with below, using a recursive call,
this is it!
def getNextLetter(previous_letter):
"""
'increments' the provide string to the next letter recursively
raises TypeError if previous_letter is not a string
returns "a" if provided previous_letter was emtpy string
"""
if not isinstance(previous_letter, str):
raise TypeError("the previous letter should be a letter, doh")
if previous_letter == '':
return "a"
for letter_location in range(len(previous_letter) - 1, -1, -1):
if previous_letter[letter_location] == "z":
return getNextLetter(previous_letter[:-1])+"a"
else:
characters = "abcdefghijklmnopqrstuvwxyz"
return (previous_letter[:-1])\
+characters[characters.find(previous_letter[letter_location])+1]
# EOF
Why not use openpyxl's get_column_letter and column_index_from_string
from openpyxl.utils import get_column_letter, column_index_from_string
# or `from openpyxl.utils.cell import get_column_letter, column_index_from_string`
def get_next_letter(s: str) -> str:
return get_column_letter(
column_index_from_string(s) + 1
).lower()
and then
>>> get_next_letter('aab')
'aac'
>>> get_next_letter('zz')
'aaa'
?
Keeping in mind that this solution only works in [A, ZZZ[.
I fact what you want to achieve is increment a number expressed in base26 (using the 26 alphabet letters as symbols).
We all know decimal base that we use daily.
We know hexadecimal that is in fact base16 with symbols including digits and a, b, c, d, e, f.
Example : 0xff equals 15.
An approach is to convert into base10, increment the result decimal number, then convert it back to base26.
Let me explain.
I define 2 functions.
A first function to convert a string (base26) into a base10 (decimal) number.
str_tobase10("abcd") # 19010
The inverse function to convert a base10 number (decimal) to a string (base26).
base10_tostr(19010) # abcd
get_next_letter() just has to convert the string to a number, increment by one and converts back to a string.
Advantages :
pure Python, no extra lib/dependency required.
works with very long strings
Example :
get_next_letter("abcdefghijz") # abcdefghika
def str_tobase10(value: str) -> int:
n = 0
for letter in value:
n *= 26
n += ord(letter)-ord("a")+1
return n
def base10_tostr(value: int) -> str:
s = ""
n = value
while n > 26:
r = n % 26
s = chr(ord("a")-1+r) + s
n = n // 26
return chr(ord("a")-1+n) + s
def get_next_letter(value: str):
n = str_tobase10(value)
return base10_tostr(n+1)

How to convert numbers in a string without using lists?

My prof wants me to create a function that return the sum of numbers in a string but without using any lists or list methods.
The function should look like this when operating:
>>> sum_numbers('34 3 542 11')
590
Usually a function like this would be easy to create when using lists and list methods. But trying to do so without using them is a nightmare.
I tried the following code but they don't work:
>>> def sum_numbers(s):
for i in range(len(s)):
int(i)
total = s[i] + s[i]
return total
>>> sum_numbers('1 2 3')
'11'
Instead of getting 1, 2, and 3 all converted into integers and added together, I instead get the string '11'. In other words, the numbers in the string still have not been converted to integers.
I also tried using a map() function but I just got the same results:
>>> def sum_numbers(s):
for i in range(len(s)):
map(int, s[i])
total = s[i] + s[i]
return total
>>> sum_numbers('1 2 3')
'11'
Totally silly of course, but for fun:
s = '34 3 542 11'
n = ""; total = 0
for c in s:
if c == " ":
total = total + int(n)
n = ""
else:
n = n + c
# add the last number
total = total + int(n)
print(total)
> 590
This assumes all characters (apart from whitespaces) are figures.
You've definitely put some effort in here, but one part of your approach definitely won't work as-is: you're iterating over the characters in the string, but you keep trying to treat each character as its own number. I've written a (very commented) method that accomplishes what you want without using any lists or list methods:
def sum_numbers(s):
"""
Convert a string of numbers into a sum of those numbers.
:param s: A string of numbers, e.g. '1 -2 3.3 4e10'.
:return: The floating-point sum of the numbers in the string.
"""
def convert_s_to_val(s):
"""
Convert a string into a number. Will handle anything that
Python could convert to a float.
:param s: A number as a string, e.g. '123' or '8.3e-18'.
:return: The float value of the string.
"""
if s:
return float(s)
else:
return 0
# These will serve as placeholders.
sum = 0
current = ''
# Iterate over the string character by character.
for c in s:
# If the character is a space, we convert the current `current`
# into its numeric representation.
if c.isspace():
sum += convert_s_to_val(current)
current = ''
# For anything else, we accumulate into `current`.
else:
current = current + c
# Add `current`'s last value to the sum and return.
sum += convert_s_to_val(current)
return sum
Personally, I would use this one-liner, but it uses str.split():
def sum_numbers(s):
return sum(map(float, s.split()))
No lists were used (nor harmed) in the production of this answer:
def sum_string(string):
total = 0
if len(string):
j = string.find(" ") % len(string) + 1
total += int(string[:j]) + sum_string(string[j:])
return total
If the string is noisier than the OP indicates, then this should be more robust:
import re
def sum_string(string):
pattern = re.compile(r"[-+]?\d+")
total = 0
match = pattern.search(string)
while match:
total += int(match.group())
match = pattern.search(string, match.end())
return total
EXAMPLES
>>> sum_string('34 3 542 11')
590
>>> sum_string(' 34 4 ')
38
>>> sum_string('lksdjfa34adslkfja4adklfja')
38
>>> # and I threw in signs for fun
...
>>> sum_string('34 -2 45 -8 13')
82
>>>
If you want to be able to handle floats and negative numbers:
def sum_numbers(s):
sm = i = 0
while i < len(s):
t = ""
while i < len(s) and not s[i].isspace():
t += s[i]
i += 1
if t:
sm += float(t)
else:
i += 1
return sm
Which will work for all cases:
In [9]: sum_numbers('34 3 542 11')
Out[9]: 590.0
In [10]: sum_numbers('1.93 -1 23.12 11')
Out[10]: 35.05
In [11]: sum_numbers('')
Out[11]: 0
In [12]: sum_numbers('123456')
Out[12]: 123456.0
Or a variation taking slices:
def sum_numbers(s):
prev = sm = i = 0
while i < len(s):
while i < len(s) and not s[i].isspace():
i += 1
if i > prev:
sm += float(s[prev:i])
prev = i
i += 1
return sm
You could also use itertools.groupby which uses no lists, using a set of allowed chars to group by:
from itertools import groupby
def sum_numbers(s):
allowed = set("0123456789-.")
return sum(float("".join(v)) for k,v in groupby(s, key=allowed.__contains__) if k)
which gives you the same output:
In [14]: sum_numbers('34 3 542 11')
Out[14]: 590.0
In [15]: sum_numbers('1.93 -1 23.12 11')
Out[15]: 35.05
In [16]: sum_numbers('')
Out[16]: 0
In [17]: sum_numbers('123456')
Out[17]: 123456.0
Which if you only have to consider positive ints could just use str.isdigit as the key:
def sum_numbers(s):
return sum(int("".join(v)) for k,v in groupby(s, key=str.isdigit) if k)
Try this:
def sum_numbers(s):
sum = 0
#This string will represent each number
number_str = ''
for i in s:
if i == ' ':
#if it is a whitespace it means
#that we have a number so we incease the sum
sum += int(number_str)
number_str = ''
continue
number_str += i
else:
#add the last number
sum += int(number_str)
return sum
You could write a generator:
def nums(s):
idx=0
while idx<len(s):
ns=''
while idx<len(s) and s[idx].isdigit():
ns+=s[idx]
idx+=1
yield int(ns)
while idx<len(s) and not s[idx].isdigit():
idx+=1
>>> list(nums('34 3 542 11'))
[34, 3, 542, 11]
Then just sum that:
>>> sum(nums('34 3 542 11'))
590
or, you could use re.finditer with a regular expression and a generator construction:
>>> sum(int(m.group(1)) for m in re.finditer(r'(\d+)', '34 3 542 11'))
590
No lists used...
def sum_numbers(s):
total=0
gt=0 #grand total
l=len(s)
for i in range(l):
if(s[i]!=' '):#find each number
total = int(s[i])+total*10
if(s[i]==' ' or i==l-1):#adding to the grand total and also add the last number
gt+=total
total=0
return gt
print(sum_numbers('1 2 3'))
Here each substring is converted to number and added to grant total
If we omit the fact eval is evil, we can solve that problem with it.
def sum_numbers(s):
s = s.replace(' ', '+')
return eval(s)
Yes, that simple. But i won't put that thing in production.
And sure we need to test that:
from hypothesis import given
import hypothesis.strategies as st
#given(list_num=st.lists(st.integers(), min_size=1))
def test_that_thing(list_num):
assert sum_numbers(' '.join(str(i) for i in list_num)) == sum(list_num)
test_that_thing()
And it would raise nothing.

Python using recursion to take a mixed string and add up the integers in the string

I am trying to use recursion to take a mixed string and add the values on the integers. An example input would be "ab4h5h6" and the out put would be 15.
Here is my code so far
def toNumber(s):
total = 0
if len(s) == 0:
return 0
else:
first = s[0]
rest = s[1:]
num_rest = toNumber(s[1:])
if first.isdigit()== True:
return int(first) + total
else:
if rest.isdigit()== True:
return int(rest) + int(num_rest)
I have tried many different things but I just can't seem to get the desired result.
You don't need to care if the rest is a digit; just add the value of first (which is 0 if not a digit) plus the recursive result:
def toNumber(s):
if not s:
return 0
first = s[0]
value = int(first) if first.isdigit() else 0
return value + toNumber(s[1:])
Other notes:
Empty strings are 'falsey'; so not s is only true if the string is empty. len(s) == 0 can thus be reduced to not s.
There is no need to use == True on boolean tests, that is what if already does for you.
Demo:
>>> def toNumber(s):
... if not s:
... return 0
... first = s[0]
... value = int(first) if first.isdigit() else 0
... return value + toNumber(s[1:])
...
>>> toNumber('ab4h5h6')
15
The very shortest :
toNumber = lambda s: bool(s) and ((s[0].isdigit() and int(s[0])) + toNumber(s[1:]))
If you don't need recursion :
toNumber = lambda s: sum(int(i) for i in s if i.isdigit())
or even one character shorter, although less pythonic :
toNumber = lambda s: sum(map(int,filter(str.isdigit,s))))
You're over-complicating things. The recursion should always be to return the number value of the current character plus the result of the function called on the rest of the string:
def toNumber(s):
if len(s) == 0:
return 0
first = s[0]
rest = s[1:]
numFirst = 0
if first.isdigit():
numFirst = int(first)
return num_first + toNumber(rest)
Here's another solution.
Strategy: recklessly treat each number as an int and catch the exceptions
def toNumber(s):
if len(s) == 0:
return 0
try:
return int(s[:1]) + toNumber(s[1:])
except ValueError:
return toNumber(s[1:])
And here's a non-recursive version employing the same strategy
def toNumberNonRecursive(s):
total = 0
for c in s:
try:
total += int(c)
except ValueError:
# not an int
pass
return total
Output:
>>> print(toNumber('1a2b3c'))
6
>>> print(toNumber(''))
0
>>> print(toNumber('abc'))
0
>>> print(toNumber('w48957jmc98(&H(*&398cmdi98'))
87

How to reverse an int in python?

I'm creating a python script which prints out the whole song of '99 bottles of beer', but reversed. The only thing I cannot reverse is the numbers, being integers, not strings.
This is my full script,
def reverse(str):
return str[::-1]
def plural(word, b):
if b != 1:
return word + 's'
else:
return word
def line(b, ending):
print b or reverse('No more'), plural(reverse('bottle'), b), reverse(ending)
for i in range(99, 0, -1):
line(i, "of beer on the wall")
line(i, "of beer"
print reverse("Take one down, pass it around")
line(i-1, "of beer on the wall \n")
I understand my reverse function takes a string as an argument, however I do not know how to take in an integer, or , how to reverse the integer later on in the script.
Without converting the number to a string:
def reverse_number(n):
r = 0
while n > 0:
r *= 10
r += n % 10
n /= 10
return r
print(reverse_number(123))
You are approaching this in quite an odd way. You already have a reversing function, so why not make line just build the line the normal way around?
def line(bottles, ending):
return "{0} {1} {2}".format(bottles,
plural("bottle", bottles),
ending)
Which runs like:
>>> line(49, "of beer on the wall")
'49 bottles of beer on the wall'
Then pass the result to reverse:
>>> reverse(line(49, "of beer on the wall"))
'llaw eht no reeb fo selttob 94'
This makes it much easier to test each part of the code separately and see what's going on when you put it all together.
Something like this?
>>> x = 123
>>> str(x)
'123'
>>> str(x)[::-1]
'321'
best way is
x=12345
a=str(x)[::-1]\\ In this process i have create string of inverse of integer (a="54321")
a=int(a) \\ Here i have converted string a in integer
or
one line code is
a=int(str(x)[::-1]))
def reverse(x):
re = 0
negative = x < 0
MAX_BIG = 2 ** 31 -1
MIN_BIG = -2 ** 31
x = abs(x)
while x != 0:
a = int(x % 10)
re = re * 10 + a
x = int(x // 10)
reverse = -1 * re if negative else re
return 0 if reverse < MIN_BIG or reverse > MAX_BIG else reverse
this is for 32 - bit integer ( -2^31 ; 2^31-1 )
def reverse_number(n):
r = 0
while n > 0:
r = (r*10) + (n % 10)
print(r)
r *=10
n //= 10
return r
print(reverse_number(123))
You can cast an integer to string with str(i) and then use your reverse function.
The following line should do what you are looking for:
def line(b, ending):
print reverse(str(b)) or reverse('No more'), plural(reverse('bottle'),reverse(str(b))), reverse(ending)
Original number is taken in a
a = 123
We convert the int to string ,then reverse it and again convert in int and store reversed number in b
b = int("".join(reversed(str(a))))
Print the values of a and b
print(a,b)
def reverse_number(n):
r = 0
while n > 0:
r *= 10
r += n % 10
n /= 10
return r
print(reverse_number(123))
This code will not work if the number ends with zeros, example 100 and 1000 return 1
def reverse(num):
rev = 0
while(num != 0):
reminder = num % 10
rev = (rev * 10 ) + reminder
num = num // 10
print ("Reverse number is : " , rev )
num=input("enter number : ")
reverse(int(num))
#/ always results into float
#// division that results into whole number adjusted to the left in the number line
I think the following code should be good to reverse your positive integer.
You can use it as a function in your code.
n = input() # input is always taken as a string
rev = int(str(n)[::-1])
If you are having n as integer then you need to specify it as str here as shown. This is the quickest way to reverse a positive integer
import math
def Function(inputt):
a = 1
input2 = inputt
while(input2 > 9):
input2 = input2/10
a = a + 1
print("There are ", a, " numbers ")
N = 10
m = 1
print(" THe reverse numbers are: ")
for i in range(a):
l = (inputt%N)/m
print(math.floor(l), end = '')
N = N*10
m = m*10
print(" \n")
return 0
enter = int(input("Enter the number: "))
print(Function(enter))
More robust solution to handle negative numbers:
def reverse_integer(num):
sign = [1,-1][num < 0]
output = sign * int(str(abs(num))[::-1])
An easy and fast way to do it is as follows:
def reverse(x: int|str) -> int:
reverse_x = int(''.join([dgt for dgt in reversed(num:=str(x)) if dgt != '-']))
if '-' in num:
reverse_x = -reverse_x'
return reverse_x
First we create a list (using list comprehension) of the digits in reverse order. However, we must exclude the sign (otherwise the number would turn out like [3, 2, 1, -]). We now turn the list into a string using the ''.join() method.
Next we check if the original number had a negative sign in it. If it did, we would add a negative sign to reverse_x.
Easily you can write this class:
class reverse_number:
def __init__(self,rvs_num):
self.rvs_num = rvs_num
rvs_ed = int(str(rvs_num)[::-1])
print(rvs_ed)
You can use it by writing:
reverse_number(your number)
I have written it in a different way, but it works
def isPalindrome(x: int) -> bool:
if x<0:
return False
elif x<10:
return True
else:
rev=0
rem = x%10
quot = x//10
rev = rev*10+rem
while (quot>=10):
rem = quot%10
quot = quot//10
rev = rev*10+rem
rev = rev*10+quot
if rev==x:
return True
else:
return False
res=isPalindrome(1221)

Convert fraction to float?

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.
maybe something like this (2.6+)
from fractions import Fraction
float(sum(Fraction(s) for s in '1 2/3'.split()))
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
http://ideone.com/ItifKv
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.
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
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).
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".
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
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.
>>> 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

Categories

Resources