如何在 Python 中将货币字符串转换为浮点数?
- 2025-03-04 08:27:00
- admin 原创
- 66
问题描述:
我有一些表示具有特定货币格式的数字的字符串,例如:
money="$6,150,593.22"
我想把这个字符串转换成数字
6150593.22
实现这一目标的最佳方法是什么?
解决方案 1:
尝试一下:
from re import sub
from decimal import Decimal
money = '$6,150,593.22'
value = Decimal(sub(r'[^d.]', '', money))
这具有一些优点,因为它使用Decimal
而不是float
(这更适合表示货币)并且它还通过不对特定货币符号进行硬编码来避免任何区域设置问题。
解决方案 2:
如果您的语言环境设置正确,您可以使用locale.atof
,但您仍然需要手动去掉“$”:
>>> import locale
>>> locale.setlocale(locale.LC_ALL, 'en_US.UTF8')
'en_US.UTF8'
>>> money = "$6,150,593.22"
>>> locale.atof(money.strip("$"))
6150593.2199999997
解决方案 3:
我发现这个babel
软件包非常有助于解决问题
局部 解析
并且需要全局更改语言环境
它使得在本地化版本中解析数字变得容易:
>>> babel.numbers.parse_decimal('1,024.64', locale='en')
Decimal('1024.64')
>>> babel.numbers.parse_decimal('1.024,64', locale='de')
Decimal('1024.64')
>>>
您可以使用它babel.numbers.get_currency_symbol('USD')
来去除前缀/后缀,而无需对其进行硬编码。
Hth,dtk
解决方案 4:
对于无需对货币位置或符号进行硬编码的解决方案:
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'])
amount = locale.atof(raw_numbers)
解决方案 5:
扩展以包含括号中的负数:
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
请注意,必须从 float()/Decimal() 中删除逗号。可以使用 replace() 或带有翻译表的 Translation() 将开头的 ( 转换为 -,Translate 稍快一些。Float() 速度最快,快 10-15 倍,但缺乏精度,并且可能存在区域设置问题。Decimal() 具有精度,比 locale.atof() 快 50%,但也有区域设置问题。locale.atof() 最慢,但最通用。
编辑:新str.translate
API(映射到的字符None
从函数移动str.translate
到翻译表)
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)
解决方案 6:
扩展@Andrew Clark 的回答
对于除en_US以外的其他语言环境:
>>> import re
>>> import locale
>>> locale.setlocale(locale.LC_NUMERIC, 'pt_BR.UTF8') # this is for atof()
'pt_BR.UTF8'
>>> locale.setlocale(locale.LC_MONETARY, 'pt_BR.UTF8') # this is for currency()
'pt_BR.UTF8'
>>> curr = locale.currency(6150593.22, grouping = True)
>>> curr
'R$ 6.150.593,22'
>>> re.sub('[^(d,.)]', '', curr)
'15,00'
>>> locale.atof(re.sub('[^(d,.)]', '', curr))
6150593.22
>>> 6150593.22 == locale.atof(re.sub('[^(d,.)]', '', locale.currency(6150593.22, grouping = True)))
True
必须提醒的是:货币的适当 Python 类型是十进制,而不是浮点数。
解决方案 7:
几年前我制作了这个功能来解决同样的问题。
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
解决方案 8:
此功能将土耳其价格格式转换为十进制数。
money = '1.234,75'
def make_decimal(string):
result = 0
if string:
[num, dec] = string.rsplit(',')
result += int(num.replace('.', ''))
result += (int(dec) / 100)
return result
print(make_decimal(money))
1234.75
解决方案 9:
我发现的最简单的方法,无需对货币检测进行硬编码,还可以使用Decimal
避免float
类型问题的类型:
>>> from decimal import Decimal
>>> money="$6,150,593.22"
>>> amount = Decimal("".join(d for d in money if d.isdigit() or d == '.'))
>>> amount
Decimal('6150593.22')
credit: https://www.reddit.com/r/learnpython/comments/2248mp/how_to_format_currency_without_currency_sign/cgjd1o4?utm_source=share&utm_medium=web2x
解决方案 10:
我将提供我的解决方案,希望它能够帮助那些不仅遇到问题,
而且遇到问题的人.
。
def process_currency_adaptive(currency_string: str, decimal_sep_char: str) -> float:
"""
Converts the currency string to common float format:
Format:
######.###
Example:
6150593.22
"""
# Get rid of currency symbol
currency_symbols = ["$", "€", "£", "₺"]
# Replace any occurrence of currency symbol with empty string
for symbol in currency_symbols:
currency_string = currency_string.replace(symbol, "")
if decimal_sep_char == ",":
triple_sep_char = "."
elif decimal_sep_char == ".":
triple_sep_char = ","
else:
raise ValueError("Invalid decimal separator character: {}".format(decimal_sep_char))
# Get rid of the triple separator
currency_string = currency_string.replace(triple_sep_char, "")
# There should be only one decimal_sep_char.
if currency_string.count(decimal_sep_char) != 1:
print("Error: Invalid currency format with value: {}".format(currency_string))
raise ValueError
return float(currency_string.replace(decimal_sep_char, "."))
# test process_currency
print(process_currency_adaptive("942,695", decimal_sep_char=",")) # 942.695
print(process_currency_adaptive("$6,150,593.22", decimal_sep_char=".")) # 6150593.22
扫码咨询,免费领取项目管理大礼包!