escape - Python no está ordenando unicode correctamente. Strcoll no ayuda
unicode escape python (6)
@gnibbler, usar PyICU con la función sorted () funciona en un entorno Python3. Después de investigar un poco la documentación de la API de ICU y algunos experimentos, encontré la función getSortKey () :
import PyICU
collator = PyICU.Collator.createInstance(PyICU.Locale(''de_DE.UTF-8''))
sorted([''a'',''b'',''c'',''ä''],key=collator.getSortKey)
que produce la colación deseada:
[''a'', ''ä'', ''b'', ''c'']
en lugar de la colación no deseada:
sorted([''a'',''b'',''c'',''ä''])
[''a'', ''b'', ''c'', ''ä'']
Tengo un problema con la clasificación de listas utilizando la intercalación de Unicode en Python 2.5.1 y 2.6.5 en OSX, así como en Linux.
import locale
locale.setlocale(locale.LC_ALL, ''pl_PL.UTF-8'')
print [i for i in sorted([u''a'', u''z'', u''ą''], cmp=locale.strcoll)]
Que debe imprimir:
[u''a'', u''ą'', u''z'']
Pero en cambio imprime:
[u''a'', u''z'', u''ą'']
Resumiendo, parece como si se hubiera roto el strcoll. Lo probé con varios tipos de variables (cadenas codificadas no Unicode).
¿Qué hago mal?
Saludos cordiales, Tomasz Kopczuk.
Aparentemente, la única manera de que la clasificación funcione en todas las plataformas es utilizar la biblioteca ICU con enlaces PyICU ( PyICU en PyPI ).
En OS X: sudo port install py26-pyicu
, el error de sudo port install py26-pyicu
descrito aquí: https://svn.macports.org/ticket/23429 (oh, la alegría de usar macports).
Lamentablemente, la documentación de PyICUs es muy deficiente, pero logré averiguar cómo se hace:
import PyICU
collator = PyICU.Collator.createInstance(PyICU.Locale(''pl_PL.UTF-8''))
print [i for i in sorted([u''a'', u''z'', u''ą''], cmp=collator.compare)]
lo que da:
[u''a'', u''ą'', u''z'']
Otro pro - @bobince: es seguro para la ejecución de subprocesos, por lo que no es inútil cuando se configuran entornos locales de solicitud.
Aquí es cómo me las arreglé para ordenar el idioma persa correctamente (sin PyICU) (usando Python 3.x):
Primero establezca la configuración regional (no olvide importar la configuración regional y la plataforma )
if platform.system() == ''Linux'':
locale.setlocale(locale.LC_ALL, ''fa_IR.UTF-8'')
elif platform.system() == ''Windows'':
locale.setlocale(locale.LC_ALL, ''Persian_Iran.1256'')
else:
pass (or any other OS)
Luego ordénalo usando la clave:
a = [''ا'',''ب'',''پ'',''ت'',''ث'',''ج'',''چ'',''ح'',''خ'',''د'',''ذ'',''ر'',''ز'',''ژ'',''س'',''ش'',''ص'',''ض'',''ط'',''ظ'',''ع'',''غ'',''ف'',''ق'',''ک'',''گ'',''ل'',''م'',''ن'',''و'',''ه'',''ي'']
print(sorted(a,key=locale.strxfrm))
Para lista de objetos:
a = [{''id'':"ا"},{''id'':"ب"},{''id'':"پ"},{''id'':"ت"},{''id'':"ث"},{''id'':"ج"},{''id'':"چ"},{''id'':"ح"},{''id'':"خ"},{''id'':"د"},{''id'':"ذ"},{''id'':"ر"},{''id'':"ز"},{''id'':"ژ"},{''id'':"س"},{''id'':"ش"},{''id'':"ص"},{''id'':"ض"},{''id'':"ط"},{''id'':"ظ"},{''id'':"ع"},{''id'':"غ"},{''id'':"ف"},{''id'':"ق"},{''id'':"ک"},{''id'':"گ"},{''id'':"ل"},{''id'':"م"},{''id'':"ن"},{''id'':"و"},{''id'':"ه"},{''id'':"ي"}]
print(sorted(a, key=lambda x: locale.strxfrm(x[''id'']))
Finalmente puedes devolver el local:
locale.setlocale(locale.LC_ALL, '''')
En ubuntu lucid, la ordenación con cmp parece funcionar bien, pero mi codificación de salida es incorrecta.
>>> import locale
>>> locale.setlocale(locale.LC_ALL, ''pl_PL.UTF-8'')
''pl_PL.UTF-8''
>>> print [i for i in sorted([u''a'', u''z'', u''ą''], cmp=locale.strcoll)]
[u''a'', u''/u0105'', u''z'']
Usar la tecla con locale.strxfrm no funciona a menos que me esté faltando algo
>>> print [i for i in sorted([u''a'', u''z'', u''ą''], key=locale.strxfrm)]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: ''ascii'' codec can''t encode character u''/u0105'' in position 0: ordinal not in range(128)
Solo para agregar a la investigación de tkopczuk: Este es definitivamente un error de gcc, al menos para la versión 4.2.1 en OS X 10.6.4. Puede reproducirse llamando a C strcoll()
directamente como en este fragmento .
EDITAR: Aún en el mismo sistema, encuentro que para las versiones UTF-8 de de_DE, fr_FR, pl_PL, el problema está ahí, pero para las versiones ISO-88591 de fr_FR y de_DE, el orden es correcto. Desafortunadamente para el OP, ISO-88592 pl_PL también tiene errores:
The order for Polish ISO-8859 is:
LATIN SMALL LETTER A
LATIN SMALL LETTER Z
LATIN SMALL LETTER A WITH OGONEK
The LC_COLLATE culture and encoding settings were pl_PL, ISO8859-2.
The order for Polish Unicode is:
LATIN SMALL LETTER A
LATIN SMALL LETTER Z
LATIN SMALL LETTER A WITH OGONEK
The LC_COLLATE culture and encoding settings were pl_PL, UTF8.
The order for German Unicode is:
LATIN SMALL LETTER A
LATIN SMALL LETTER Z
LATIN SMALL LETTER A WITH DIAERESIS
The LC_COLLATE culture and encoding settings were de_DE, UTF8.
The order for German ISO-8859 is:
LATIN SMALL LETTER A
LATIN SMALL LETTER A WITH DIAERESIS
LATIN SMALL LETTER Z
The LC_COLLATE culture and encoding settings were de_DE, ISO8859-1.
The order for Fremch ISO-8859 is:
LATIN SMALL LETTER A
LATIN SMALL LETTER E WITH ACUTE
LATIN SMALL LETTER Z
The LC_COLLATE culture and encoding settings were fr_FR, ISO8859-1.
The order for French Unicode is:
LATIN SMALL LETTER A
LATIN SMALL LETTER Z
LATIN SMALL LETTER E WITH ACUTE
The LC_COLLATE culture and encoding settings were fr_FR, UTF8.
import locale
from functools import cmp_to_key
iterable = [u''a'', u''z'', u''ą'']
sorted(iterable, key=cmp_to_key(locale.strcoll)) # locale-aware sort order