2009-11-27 10 views
16

Tipo de like this question, pero a la inversa.¿Convertir fracción a flotar?

Dada una cadena como 1, 1/2 o 1 2/3, ¿cuál es la mejor manera de convertirla en una carroza? Estoy pensando en usar expresiones regulares caso por caso, pero tal vez alguien sepa de una mejor manera o una solución preexistente. Esperaba poder usar eval, pero creo que el tercer caso lo impide.

Respuesta

5

Pellizqué James' answer un poco.

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

2

Eso podría ser una solución sucia, pero podría convertir espacios en un signo + para resolver el tercer caso (o en un - si su fracción es negativa).

0

Dependiendo de qué sintaxis quieres apoyar para sus fracciones, eval('+'.join(s.split())) (con verdadera división en su lugar - es decir, Python 3 o from __future__ import division en Python 2 -. Se podrían funcionar cubriría todos los casos que usted menciona, en particular, ..

5

Aunque usted debe stear clara de eval completamente Quizá alguna versión más refinada de:

num,den = s.split('/') 
wh, num = num.split() 
result = wh + (float(num)/float(den)) 

Lo sentimos, destinado a ser num.split no s.split, y yesos Editado

26

.. tal vez algo l Ike this (2.6+)

from fractions import Fraction 
float(sum(Fraction(s) for s in '1 2/3'.split())) 
+0

Algunas de estas otras soluciones de trabajo también, pero éste parece el más elegante. ¡Funciona genial! Gracias una tonelada. – mpen

+0

No solo más elegante, sino también la más precisa –

+0

Como señaló la respuesta de Shnaader, tenga cuidado con los signos negativos. – jprete

1

Esta implementación evita el uso de eval y funciona en las versiones anteriores a 2.6 de 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: return i # if d is None, then n is also None 
    if n is None: i, n = 0, i 
    return float(i) + float(n)/float(d) 

Para probar:

>>> for x in ['1', '1/2', '1 2/3']: print parse(x) 
... 
1 
0.5 
1.66666666667 
0
>>> 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 
+0

1) eval es una exageración peligrosa para esto. 2) ¿Por qué dividir y convertir la cadena solo para unirla de nuevo? ¿Por qué no usar 'eval (s)'? –

+0

@NedBatchelder intente hacer esto sin la división, no funcionará como un flotador y, por lo tanto, evaluará a 0. – jimh

2

veo que ya hay varias buenas respuestas aquí, pero he tenido buena suerte con esto. También tiene la ventaja de que tolerará cadenas que no sean fracciones si está analizando conjuntos mixtos de datos, por lo que no es necesario verificar si se trata de una cadena de fracciones o no.

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 
+1

Oye ... mintió sobre su último caso de prueba. ''-3 1/2'' da como resultado' -2.5'. – mpen

+0

Gracias Marcar, todo arreglado! –

+0

No señor, usted rompió el caso positivo entero + fracción. Cuando 'leading' es positivo obtienes' whole + (frac * -1 * 0) 'que por supuesto borra la parte fraccionaria. – mpen

2
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 

También puede manejar "2 1/1e-8", "-1/3" y "1/5E3".

+0

No cubre uno de los ejemplos en mi pregunta, '1 1/2' (una y media). – mpen

+0

Editado ahora para manejar eso. – nvd

+0

Parece que rompiste el caso 'solo una fracción', por ejemplo, '1/3'. http://ideone.com/pa5cAg – mpen