web-dev-qa-db-fra.com

Comment convertir une chaîne de devise en un nombre à virgule flottante en Python?

J'ai des chaînes représentant des nombres avec un format de devise spécifique, par exemple:

money="$6,150,593.22"

Je veux convertir cette chaîne en nombre

6150593.22

Quel est le meilleur moyen d'y parvenir?

25
Javier Novoa C.

Essaye ça:

from re import sub
from decimal import Decimal

money = '$6,150,593.22'
value = Decimal(sub(r'[^\d.]', '', money))

Cela présente certains avantages, car il utilise Decimal au lieu de float (ce qui est mieux pour représenter la devise) et évite également les problèmes de paramètres régionaux en ne codant pas en dur un symbole monétaire spécifique.

39
Andrew Hare

Si vos paramètres régionaux sont définis correctement, vous pouvez utiliser locale.atof , mais vous devrez tout de même supprimer le '$' manuellement:

>>> import locale
>>> locale.setlocale(locale.LC_ALL, 'en_US.UTF8')
'en_US.UTF8'
>>> money = "$6,150,593.22"
>>> locale.atof(money.strip("$"))
6150593.2199999997
14
Andrew Clark

Développer pour inclure des nombres négatifs entre parenthèses:

In [1]: import locale, string

In [2]: from decimal import Decimal

In [3]: n = ['$1,234.56','-$1,234.56','($1,234.56)', '$ -1,234.56']

In [4]: tbl = string.maketrans('(','-')

In [5]: %timeit -n10000 [locale.atof( x.translate(tbl, '$)')) for x in n]
10000 loops, best of 3: 31.9 æs per loop

In [6]: %timeit -n10000 [Decimal( x.translate(tbl, '$,)')) for x in n]
10000 loops, best of 3: 21 æs per loop

In [7]: %timeit -n10000 [float( x.replace('(','-').translate(None, '$,)')) for x in n]
10000 loops, best of 3: 3.49 æs per loop

In [8]: %timeit -n10000 [float( x.translate(tbl, '$,)')) for x in n]
10000 loops, best of 3: 2.19 æs per loop

Notez que les virgules doivent être supprimées de float ()/Decimal (). Replace () ou translate () avec une table de traduction peut être utilisé pour convertir l’ouverture (to -, la traduction est légèrement plus rapide. Float () est le plus rapide de 10 à 15 fois, mais manque de précision et pourrait poser des problèmes de localisation. ) a une précision et est 50% plus rapide que locale.atof (), mais présente également des problèmes de localisation. locale.atof () est la plus lente, mais la plus générale.

Modifier: nouvelle API str.translate (les caractères mappés sur None sont passés de la fonction str.translate à la table de traduction)

In [1]: import locale, string
        from decimal import Decimal

        locale.setlocale(locale.LC_ALL, '')

        n = ['$1,234.56','-$1,234.56','($1,234.56)', '$ -1,234.56']

In [2]: tbl = str.maketrans('(', '-', '$)')
        %timeit -n10000 [locale.atof( x.translate(tbl)) for x in n]
18 µs ± 296 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [3]: tbl2 = str.maketrans('(', '-', '$,)')
        %timeit -n10000 [Decimal( x.translate(tbl2)) for x in n]
3.77 µs ± 50.8 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [4]: %timeit -n10000 [float( x.translate(tbl2)) for x in n]
3.13 µs ± 66.3 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [5]: tbl3 = str.maketrans('', '', '$,)')
        %timeit -n10000 [float( x.replace('(','-').translate(tbl3)) for x in n]
3.51 µs ± 84.8 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
5
bjacobowski

Pour une solution sans codage en dur de la position monétaire ou du symbole:

raw_price = "17,30 €"
import locale
locale.setlocale(locale.LC_ALL, 'fr_FR.UTF8')
conv = locale.localeconv()
raw_numbers = raw_price.strip(conv['currency_symbol'].decode('utf-8'))
amount = locale.atof(raw_numbers)
5
kokociel

J'ai trouvé le paquet babel très utile pour contourner le problème 

Il est facile d'analyser un nombre dans un rendu localisé:

>>> babel.numbers.parse_decimal('1,024.64', locale='en')                                                                                                                           
Decimal('1024.64')
>>> babel.numbers.parse_decimal('1.024,64', locale='de')
Decimal('1024.64')
>>>

Vous pouvez utiliser babel.numbers.get_currency_symbol('USD') pour supprimer les préfixes/suffixes sans les coder en dur.

Hth, Dtk

2
dtk

J'ai créé cette fonction il y a quelques années pour résoudre le même problème.

def money(number):
    number = number.strip('$')
    try:
        [num,dec]=number.rsplit('.')
        dec = int(dec)
        aside = str(dec)
        x = int('1'+'0'*len(aside))
        price = float(dec)/x
        num = num.replace(',','')
        num = int(num)
        price = num + price
    except:
        price = int(number)
    return price
1
user3403267