2

我得到了这种奇怪的行为:

>>> locale.setlocale(locale.LC_ALL, 'de_DE.utf-8')
'de_DE.utf-8'
>>> sorted([u'<NULL', u'NULL>', u'<NULL>', u'NULL', u'a'], cmp=locale.strcoll)
[u'a', u'<NULL', u'<NULL>', u'NULL', u'NULL>']
>>> sorted(['<NULL', 'NULL>', '<NULL>', 'NULL', 'a'], cmp=locale.strcoll)
['a', 'NULL', 'NULL>', '<NULL', '<NULL>']

虽然可以在“a”之后对“<NULL”进行排序,但令我困扰的是,对于 unicode“<NULL”<“NULL”而 ANSI“NULL”<“<NULL”,尽管排序规则是相同的。

有没有办法解决这个问题?

更新:PyICU 给出的结果与上述两个不同。

>>> import PyICU
collator = PyICU.Collator.createInstance(PyICU.Locale('de_DE.UTF-8'))
>>> sorted([u'<NULL', u'NULL>', u'<NULL>', u'NULL', u'a'], cmp=collator.compare)
[u'<NULL', u'<NULL>', u'a', u'NULL', u'NULL>']
4

2 回答 2

2

一种解决方法是始终使用 unicode(或字节字符串)作为键:

import locale
from functools import cmp_to_key

@cmp_to_key
def strcoll(a, b):
    if isinstance(a, str):
        a = a.decode('utf-8')
    if isinstance(b, str):
        b = b.decode('utf-8')
    return locale.strcoll(a, b)

那么以下应该给出相同的输出:

sorted([u'<NULL', u'NULL>', u'<NULL>', u'NULL', u'a'], key=strcoll)
sorted(['<NULL', 'NULL>', '<NULL>', 'NULL', 'a'], key=strcoll)

我会使用key而不是cmp因为它更便携。

一种更简单的方法是简单地将所有字符串明确地保留为 unicodes/bytes:

def to_unicode(s):
    return s.decode('utf-8') if isinstance(s, str) else s

the_list = [...]
the_list = [to_unicode(elem) for elem in the_list]

str这种方法的优点是在and之间进行一次转换unicode,而另一种方法在每次比较时进行转换(即使使用keyand cmp_to_key)。

于 2013-04-02T18:57:54.093 回答
0

解决方法是使用 de_DE.utf-8 以外的德语语言环境。有趣的是,它适用于例如 de_AT.utf-8。

>>> locale.setlocale(locale.LC_ALL, 'en_US.utf-8')
'en_US.utf-8'
>>> sorted([u'<NULL', u'NULL>', u'<NULL>', u'NULL', u'a'], cmp=locale.strcoll)
[u'a', u'NULL', u'<NULL', u'<NULL>', u'NULL>']
>>> locale.setlocale(locale.LC_ALL, 'de_AT.utf-8')
'de_AT.utf-8'
>>> sorted([u'<NULL', u'NULL>', u'<NULL>', u'NULL', u'a'], cmp=locale.strcoll)
[u'a', u'NULL', u'<NULL', u'<NULL>', u'NULL>']
>>> locale.setlocale(locale.LC_ALL, 'de_CH.utf-8')
'de_CH.utf-8'
>>> sorted([u'<NULL', u'NULL>', u'<NULL>', u'NULL', u'a'], cmp=locale.strcoll)
[u'a', u'NULL', u'<NULL', u'<NULL>', u'NULL>']

但:

>>> locale.setlocale(locale.LC_ALL, 'de_DE.utf-8')
'de_DE.utf-8'
>>> sorted([u'<NULL', u'NULL>', u'<NULL>', u'NULL', u'a'], cmp=locale.strcoll)
[u'a', u'<NULL', u'<NULL>', u'NULL', u'NULL>']

我猜,这将其缩小为某些 Linux 系统上德语主要语言环境的错误。

于 2013-04-03T09:29:24.940 回答