61 votes

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

J'ai quelques 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 un nombre

6150593.22

Quelle est la meilleure façon d'y parvenir ?

82voto

Andrew Hare Points 159332

Essayez ça :

from re import sub
from decimal import Decimal

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

Cette méthode présente certains avantages puisqu'elle utilise Decimal au lieu de float (qui est plus adapté à la représentation des devises) et évite également les problèmes de paramètres locaux en ne codant pas en dur un symbole monétaire spécifique.

17voto

Andrew Clark Points 77748

Si vos paramètres locaux sont correctement définis, vous pouvez utiliser locale.atof mais vous devrez toujours enlever 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

9voto

dtk Points 548

J'ai trouvé le babel paquet très utile pour travailler autour

Il facilite l'analyse d'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é/suffixes sans les coder en dur.

Hth, dtk

9voto

kokociel Points 145

Pour une solution sans codage en dur de la position ou du symbole de la devise :

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)

6voto

bjacobowski Points 159

Élargissement pour inclure les 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(). Soit replace() ou translate() avec une table de traduction peut être utilisé pour convertir l'ouverture ( en -, translate est légèrement plus rapide. float() est plus rapide de 10-15x, mais manque de précision et peut présenter des problèmes de localisation. Decimal() a de la précision et est 50% plus rapide que locale.atof(), mais a aussi des problèmes locaux. locale.atof() est la plus lente, mais la plus générale.

Edit : nouveau str.translate API (caractères mis en correspondance avec None déplacé de 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)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X