在Python中将货币解析为数字

2024-09-30 08:17:53 发布

您现在位置:Python中文网/ 问答频道 /正文

我刚刚从Format numbers as currency in Python了解到Python模块babel提供{a3}来将数字格式化为货币。例如

from babel.numbers import format_currency

s = format_currency(123456.789, 'USD', locale='en_US')  # u'$123,456.79'
s = format_currency(123456.789, 'EUR', locale='fr_FR')  # u'123\xa0456,79\xa0\u20ac'

反过来呢,从货币到数字,比如$123,456,789.00-->;123456789babel提供^{}来解析本地数字,但我没有找到类似parse_currency的内容。那么,将本币解析成数字的理想方法是什么?在


我通过了Python: removing characters except digits from string。在

^{pr2}$

它不考虑十进制分隔符.。在


从字符串中删除除.之外的所有非数字字符(请参阅here

import re

# Way 1:
s = '$123,456.79'
n = re.sub("[^0-9|.]", "", s)   # 123456.79

# Way 2:
non_decimal = re.compile(r'[^\d.]+')
s = '$123,456.79'
n = non_decimal.sub('', s)      # 123456.79

它确实处理十进制分隔符.。在


但上述解决方案在

from babel.numbers import format_currency
s = format_currency(123456.789, 'EUR', locale='fr_FR')  # u'123\xa0456,79\xa0\u20ac'
new_s = s.encode('utf-8') # 123 456,79 €

如你所见,货币的格式各不相同。用一般方法将货币解析为数字的理想方法是什么?


Tags: 方法fromimportreformat货币数字fr
1条回答
网友
1楼 · 发布于 2024-09-30 08:17:53

使用巴别塔

babel文档注意到the number parsing is not fully implemented yes,但是他们做了很多工作来将货币信息输入到库中。您可以使用get_currency_name()get_currency_symbol()获取货币详细信息,还可以使用所有其他get_...函数来获取正常数字的详细信息(小数点、减号等)。在

使用这些信息,您可以从货币字符串中排除货币详细信息(名称、符号)和分组(例如美国的,)。然后将十进制细节更改为C区域设置使用的细节(-表示减号,.表示小数点)。在

这就产生了以下代码(我添加了一个对象来保存一些数据,这在进一步处理时可能会很方便):

import re, os
from babel import numbers as n
from babel.core import default_locale

class AmountInfo(object):
    def __init__(self, name, symbol, value):
        self.name = name
        self.symbol = symbol
        self.value = value

def parse_currency(value, cur):
    decp = n.get_decimal_symbol()
    plus = n.get_plus_sign_symbol()
    minus = n.get_minus_sign_symbol()
    group = n.get_group_symbol()
    name = n.get_currency_name(cur)
    symbol = n.get_currency_symbol(cur)
    remove = [plus, name, symbol, group]
    for token in remove:
        # remove the pieces of information that shall be obvious
        value = re.sub(re.escape(token), '', value)
    # change the minus sign to a LOCALE=C minus
    value = re.sub(re.escape(minus), '-', value)
    # and change the decimal mark to a LOCALE=C decimal point
    value = re.sub(re.escape(decp), '.', value)
    # just in case remove extraneous spaces
    value = re.sub('\s+', '', value)
    return AmountInfo(name, symbol, value)

#cur_loc = os.environ['LC_ALL']
cur_loc = default_locale()
print('locale:', cur_loc)
test = [ (n.format_currency(123456.789, 'USD', locale=cur_loc), 'USD')
       , (n.format_currency(-123456.78, 'PLN', locale=cur_loc), 'PLN')
       , (n.format_currency(123456.789, 'PLN', locale=cur_loc), 'PLN')
       , (n.format_currency(123456.789, 'IDR', locale=cur_loc), 'IDR')
       , (n.format_currency(123456.789, 'JPY', locale=cur_loc), 'JPY')
       , (n.format_currency(-123456.78, 'JPY', locale=cur_loc), 'JPY')
       , (n.format_currency(123456.789, 'CNY', locale=cur_loc), 'CNY')
       , (n.format_currency(-123456.78, 'CNY', locale=cur_loc), 'CNY')
       ]

for v,c in test:
    print('As currency :', c, ':', v.encode('utf-8'))
    info = parse_currency(v, c)
    print('As value    :', c, ':', info.value)
    print('Extra info  :', info.name.encode('utf-8')
                         , info.symbol.encode('utf-8'))

输出看起来很有希望(在美国地区):

^{pr2}$

它仍然适用于不同的地区(巴西以逗号作为小数点而著名):

$ export LC_ALL=pt_BR
$ ./cur.py 
locale: pt_BR
As currency : USD : b'US$123.456,79'
As value    : USD : 123456.79
Extra info  : b'D\xc3\xb3lar americano' b'US$'
As currency : PLN : b'-PLN123.456,78'
As value    : PLN : -123456.78
Extra info  : b'Zloti polon\xc3\xaas' b'PLN'
As currency : PLN : b'PLN123.456,79'
As value    : PLN : 123456.79
Extra info  : b'Zloti polon\xc3\xaas' b'PLN'
As currency : IDR : b'IDR123.457'
As value    : IDR : 123457
Extra info  : b'Rupia indon\xc3\xa9sia' b'IDR'
As currency : JPY : b'JP\xc2\xa5123.457'
As value    : JPY : 123457
Extra info  : b'Iene japon\xc3\xaas' b'JP\xc2\xa5'
As currency : JPY : b'-JP\xc2\xa5123.457'
As value    : JPY : -123457
Extra info  : b'Iene japon\xc3\xaas' b'JP\xc2\xa5'
As currency : CNY : b'CN\xc2\xa5123.456,79'
As value    : CNY : 123456.79
Extra info  : b'Yuan chin\xc3\xaas' b'CN\xc2\xa5'
As currency : CNY : b'-CN\xc2\xa5123.456,78'
As value    : CNY : -123456.78
Extra info  : b'Yuan chin\xc3\xaas' b'CN\xc2\xa5'

值得指出的是,babel存在一些编码问题。这是因为区域设置文件(在locale-data)本身确实使用不同的编码。如果你在处理你熟悉的货币,那应该不是问题。但如果你尝试不熟悉的货币,你可能会遇到问题(我刚刚了解到波兰使用iso-8859-2,而不是{})。在

相关问题 更多 >

    热门问题