代码之家  ›  专栏  ›  技术社区  ›  John Machin Santi

使用python2.X的locale模块格式化数字和货币

  •  4
  • John Machin Santi  · 技术社区  · 14 年前

    任务是将数字、货币金额和日期格式化为 unicode 以区域设置感知的方式创建字符串。

    第一次天真的数字尝试带来了希望:

    Python 2.7 (r27:82525, Jul  4 2010, 09:01:59) [MSC v.1500 32 bit (Intel)] on win32
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import locale
    >>> locale.setlocale(locale.LC_ALL, '')
    'English_Australia.1252'
    >>> locale.format("%d", 12345678, grouping=True)
    '12,345,678'
    >>> locale.format(u"%d", 12345678, grouping=True)
    u'12,345,678'
    >>>
    

    >>> locale.setlocale(locale.LC_ALL, 'French_France')
    'French_France.1252'
    >>> locale.format("%d", 12345678, grouping=True)
    '12\xa0345\xa0678'
    >>> locale.format(u"%d", 12345678, grouping=True)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "C:\python27\lib\locale.py", line 190, in format
        return _format(percent, value, grouping, monetary, *additional)
      File "C:\python27\lib\locale.py", line 211, in _format
        formatted, seps = _group(formatted, monetary=monetary)
      File "C:\python27\lib\locale.py", line 160, in _group
        left_spaces + thousands_sep.join(groups) + right_spaces,
    UnicodeDecodeError: 'ascii' codec can't decode byte 0xa0 in position 0: ordinal not in range(128)
    

    这里发生了什么?

    >>> locale.localeconv() # output edited for brevity
    {'thousands_sep': '\xa0', 'mon_thousands_sep': '\xa0', 'currency_symbol': '\x80'}
    

    >>> locale.format("%d", 12345678, grouping=True).decode(locale.getpreferredencoding())
    u'12\xa0345\xa0678'
    >>>
    

    更新1 locale.getpreferredencoding() 走的路;使用 locale.getlocale()[1]

    Python 2.7 (r27:82525, Jul  4 2010, 09:01:59) [MSC v.1500 32 bit (Intel)] on win32
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import locale
    >>> locale.getpreferredencoding(), locale.getlocale()
    ('cp1252', (None, None))
    >>> locale.setlocale(locale.LC_ALL, '')
    'English_Australia.1252'
    >>> locale.getpreferredencoding(), locale.getlocale()
    ('cp1252', ('English_Australia', '1252'))
    >>> locale.setlocale(locale.LC_ALL, 'russian_russia')
    'Russian_Russia.1251'
    >>> locale.getpreferredencoding(), locale.getlocale()
    ('cp1252', ('Russian_Russia', '1251')) #### Whoops! ####
    >>>
    

    更新2

    >>> locale.setlocale(locale.LC_ALL, 'french_france')
    'French_France.1252'
    >>> format(12345678, 'n')
    '12\xa0345\xa0678'
    >>> format(12345678, u'n') # type triggers cast to unicode somehow
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    UnicodeDecodeError: 'ascii' codec can't decode byte 0xa0 in position 2: ordinal not in range(128)
    >>> import datetime;datetime.date(1999,12,31).strftime(u'%B') # type is ignored
    'd\xe9cembre'
    >>>
    

    在所有情况下,解决方法都是只使用 str 对象调用这些方法时,获取 结果,并使用 语言环境.getlocale()[1]

    (1) 当测试/探索Windows语言环境名称不仅不同于POSIX(“frïfr”),而且冗长且没有完整的文档时,这是一个相当麻烦的问题。例如,印度的分组显然不是“每3位数”。。。我找不到用来探索这个问题的语言环境;像“印地语”和“印地语-印度”这样的尝试是行不通的。

    (2) 有些localeconv()数据是完全错误的。例如,对于韩语,货币符号如下所示 '\\' i、 一个反斜杠。我知道一些7位遗留字符集不兼容ASCII,chr(92)有时被用作本地货币符号,所以我预计 '\\' .decode('949')生成赢的符号,而不仅仅是 u'\\'

    babel 但我并不是特别想强加这样一个巨大的外部依赖。我能同时得到正确和方便吗?有什么关于 locale 我错过的模块?

    1 回复  |  直到 14 年前
        1
  •  3
  •   Martin v. Löwis    14 年前

    this list .

    编辑 :至于韩元符号,我认为故事是这样的:微软已经将韩元符号分配到与MS-DOS中的反斜杠相同的代码位置(日语版本中的日元符号也是如此)。因此,文件分隔符字符是赢的符号,并呈现为赢的符号。当他们转向Windows,后来又转向Unicode时,他们必须继续支持这一点,但他们还必须保留文件分隔符是反斜杠的属性(特别是在Unicode API中)。他们解决了这场冲突

    1. 字符\x5c实际上是反斜杠,而不是赢号
    2. 在终端应用程序中,反斜杠是 提供 作为赢的标志,那只是字体问题。
    3. 货币符号报告为\x5c:因此货币符号 反斜杠。