【发布时间】:2010-11-02 22:25:02
【问题描述】:
任务是以区域设置方式将数字、货币金额和日期格式化为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'
>>>
UPDATE 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! ####
>>>
UPDATE 2 strftime() 系列和 str.format() 存在非常相似的问题
>>> 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 对象,得到str 结果,并使用locale.getlocale()[1] 获得的编码对其进行解码
其他问题:
(1) 在测试/探索 Windows 语言环境名称不仅不同于 POSIX(“fr_FR”)而且冗长且没有完整记录时,这是一个相当大的麻烦。例如,显然印度的分组不是“每 3 位数字”......我找不到用于探索这个的语言环境;像“Hindi”和“Hindi_India”这样的尝试不起作用。
(2) 某些 localeconv() 数据完全是错误的。例如。对于韩语,货币符号为'\\',即一个反斜杠。我知道一些 7 位传统字符集与 ASCII 不兼容,并且 chr(92) 有时用于本地货币符号,所以我希望 '\\'.decode('949') 产生一个韩元符号,不仅仅是u'\\'
我知道babel 之类的模块,但我并不特别想强加这样的大外部依赖项。我可以同时获得正确性和便利性吗? locale 模块有什么我错过的吗?
【问题讨论】:
标签: python internationalization locale