2010-11-02 30 views
4

任务是以区域设置感知的方式将数字,货币金额和日期格式化为unicode字符串。用数字使用Python 2.X的区域设置模块来格式化数字和货币

先天真的尝试带来了希望:

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' 
>>> 

更新1locale.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没有与的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位数字”......我找不到用于探索这个地区的地区;像“印地语”和“印度印度”这样的尝试不起作用。 (2)一些localeconv()数据显然是错误的。例如。对于韩币,货币符号为'\\',即单个反斜杠。我知道一些7位传统字符集不是ASCII兼容的,并且chr(92)有时用于本地货币符号,所以我期望'\\' .decode('949')产生一个韩元符号,而不仅仅是u'\\'

我知道模块,如babel,但我不特别想强加一个像这样的大的外部依赖。我能同时获得正确性和便利吗?是否有关于我错过的locale模块?

回答

3

您似乎错过的语言环境模块的事情是它暴露了您的操作系统供应商的(真正的:C库供应商的)语言环境概念。因此,在Windows上,您将不得不使用Windows语言环境名称,使用您的操作系统供应商的文档来查明支持的名称是什么。谷歌搜索“窗口区域设置名称”迅速提出this list

locale.format并不真正支持Unicode是2.x限制;尝试Python 3.1。我认为这个故事是这样的:微软已经将Won标志分配到与MS-DOS中的反斜杠相同的代码位置(对于日文版本中的日元标志也是如此)。结果,文件分隔符字符是Won符号,并且像这样呈现。当他们转移到Windows,然后转移到Unicode时,他们必须继续支持这一点,但他们也必须保留文件分隔符是反斜杠(特别是在Unicode API中)的属性。他们解决了这个矛盾,使

  1. 字符\ x5c真的是反斜杠,而不是获签
  2. 在终端应用中,反斜杠呈现为赢得标志;这只是一个字体问题。
  3. 货币符号被报告为\ x5c:所以货币符号真的是的反斜杠。