Jak sortować ciągi unicode Alfabetycznie w Pythonie?

Python sortuje według wartości bajtów domyślnie, co oznacza, że é pojawia się po z i innych równie zabawnych rzeczach. Jaki jest najlepszy sposób sortowania alfabetycznego w Pythonie?

Czy jest do tego biblioteka? Nic nie znalazłem. Preferowane sortowanie powinno mieć obsługę języka, więc rozumie, że åäö powinno być sortowane po z w języku szwedzkim, ale ü powinno być sortowane po u, itp. Obsługa Unicode jest więc wymaganiem.

Jeśli nie ma dla niego biblioteki, jaki jest najlepszy sposób żeby to zrobić? Po prostu zrobić mapowanie z litery do wartości całkowitej i mapować łańcuch do listy całkowitej z tym?

Author: Georg Schölly, 2009-07-08

11 answers

Biblioteka IBM ICU robi to (i wiele więcej). Posiada wiązania Pythona: PyICU .

Update : podstawowa różnica w sortowaniu pomiędzy ICU i locale.strcoll polega na tym, że ICU używa pełnego Unicode Collation Algorithm podczas gdy strcoll używa ISO 14651.

Różnice między tymi dwoma algorytmami są krótko podsumowane tutaj: http://unicode.org/faq/collation.html#13 . są to raczej egzotyczne przypadki szczególne, które rzadko powinny mieć znaczenie w praktyce.

>>> import icu # pip install PyICU
>>> sorted(['a','b','c','ä'])
['a', 'b', 'c', 'ä']
>>> collator = icu.Collator.createInstance(icu.Locale('de_DE.UTF-8'))
>>> sorted(['a','b','c','ä'], key=collator.getSortKey)
['a', 'ä', 'b', 'c']
 66
Author: Rafał Dowgird,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-22 11:04:40

Nie widzę tego w odpowiedziach. Moja aplikacja sortuje według ustawień regionalnych używając standardowej biblioteki Pythona. To całkiem proste.

# python2.5 code below
# corpus is our unicode() strings collection as a list
corpus = [u"Art", u"Älg", u"Ved", u"Wasa"]

import locale
# this reads the environment and inits the right locale
locale.setlocale(locale.LC_ALL, "")
# alternatively, (but it's bad to hardcode)
# locale.setlocale(locale.LC_ALL, "sv_SE.UTF-8")

corpus.sort(cmp=locale.strcoll)

# in python2.x, locale.strxfrm is broken and does not work for unicode strings
# in python3.x however:
# corpus.sort(key=locale.strxfrm)

Pytanie do Lennarta i innych odpowiedzi: czy ktoś nie zna 'locale', czy to nie do tego zadania?

 48
Author: u0b34a0f6ae,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-23 14:41:14

Wypróbuj algorytm kompilacji Unicode Pythona. Może nie zrobić dokładnie tak, jak chcesz, ale wydaje się warte obejrzenia. Aby uzyskać więcej informacji na temat problemów, Zobacz ten post autorstwa Christopher Lenz.

 9
Author: Vinay Sajip,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-08 13:08:24

Możesz być również zainteresowany pyuca :

Http://jtauber.com/blog/2006/01/27/python_unicode_collation_algorithm/

Choć z pewnością nie jest to najbardziej dokładny sposób, jest to bardzo prosty sposób, aby przynajmniej trochę go dobrze. To również bije locale w webapp jak locale nie jest threadsafe i ustawia ustawienia języka całego procesu. Jest również łatwiejsza w konfiguracji niż PyICU, który opiera się na zewnętrznej bibliotece C.

Wgrałem skrypt na github jako oryginał był wyłączony w momencie pisania tego tekstu i musiałem uciekać się do buforów internetowych, aby go zdobyć: {]}

Https://github.com/href/Python-Unicode-Collation-Algorithm

Z powodzeniem użyłem tego skryptu do porządnego sortowania tekstu niemieckiego / francuskiego/włoskiego w module plone.

 8
Author: href_,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-16 13:54:45

Podsumowanie i odpowiedź Rozszerzona:

locale.strcoll w Pythonie 2, a locale.strxfrm w rzeczywistości rozwiąże problem i zrobi dobrą robotę, zakładając, że masz zainstalowane odpowiednie locale. Przetestowałem go również pod Windows, gdzie nazwy regionalne myląco różnią się od siebie, ale z drugiej strony wydaje się, że wszystkie obsługiwane lokalizacje są domyślnie zainstalowane.

ICU niekoniecznie robi to lepiej w praktyce, jednak robi to w sposób bardziej. Przede wszystkim ma poparcie dla splittery, które mogą dzielić teksty w różnych językach na słowa. Jest to bardzo przydatne dla języków, które nie mają separatorów słów. Musisz mieć korpus słów, aby użyć go jako podstawy do podziału, ponieważ nie jest to wliczone w cenę.

Ma również długie nazwy dla lokalizacji, dzięki czemu można uzyskać ładne nazwy wyświetlania dla lokalizacji, wsparcie dla innych kalendarzy niż Gregorian (chociaż nie jestem pewien, czy interfejs Pythona to obsługuje) i mnóstwo innych mniej lub bardziej niejasnych obsługa locale.

Podsumowując: Jeśli chcesz sortować alfabetycznie i zależnie od locale, możesz użyć modułu locale, chyba że masz specjalne wymagania lub potrzebujesz więcej funkcji zależnych od locale, takich jak words splitter.

 7
Author: Lennart Regebro,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-17 07:16:48

Widzę, że odpowiedzi wykonały już świetną robotę, chciałem tylko zwrócić uwagę na jedną nieefektywność kodowania w rodzaju ludzkiego . Aby zastosować selektywne tłumaczenie znaków po znakach do ciągu znaków unicode s, używa kodu:

spec_dict = {'Å':'A', 'Ä':'A'}

def spec_order(s):
    return ''.join([spec_dict.get(ch, ch) for ch in s])

Python ma o wiele lepszy, szybszy i bardziej zwięzły sposób wykonywania tego zadania pomocniczego (na ciągach Unicode-analogiczna metoda dla ciągów bajtowych ma inną i nieco mniej pomocną specyfikację!-):

spec_dict = dict((ord(k), spec_dict[k]) for k in spec_dict)

def spec_order(s):
    return s.translate(spec_dict)

The dict you pass to the translate metoda ma Unicode ordinals (nie strings) jako klucze, dlatego potrzebujemy tego kroku przebudowy z oryginalnego char-to-char spec_dict. (Wartości w dict, które przekazujesz do tłumaczenia [w przeciwieństwie do kluczy, które muszą być porządkami] mogą być porządkami Unicode, dowolnymi ciągami Unicode lub None, aby usunąć odpowiedni znak jako część tłumaczenia, więc łatwo jest określić "ignoruj określony znak do celów sortowania", "map ä do AE do celów sortowania" i tym podobne).

W Pythonie 3, ty można uzyskać krok "odbudowania" prostszy, np.:

spec_dict = ''.maketrans(spec_dict)

Zobacz docs aby dowiedzieć się więcej o innych sposobach użycia tej statycznej metody maketrans w Pythonie 3.

 6
Author: Alex Martelli,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-08 14:57:16

Kompletne rozwiązanie UCA

Najprostszym, najłatwiejszym i najprostszym sposobem na to jest wywołanie modułu Biblioteki Perla, Unicode::Collate::Locale, który jest podklasą standardowego modułu Unicode::Collate. Wystarczy przekazać konstruktorowi wartość locale "xv" dla Szwecji.

(możesz nie doceniać tego w przypadku szwedzkiego tekstu, ale ponieważ Perl używa abstrakcyjnych znaków, możesz użyć dowolnego punktu kodu Unicode proszę - bez względu na platformę lub budowę! Niewiele języków oferuje taką wygodę. Wspominam o tym, bo ostatnio dużo walczyłem z Javą o ten szalony problem.)

Problem polega na tym, że nie wiem, jak uzyskać dostęp do modułu Perla z Pythona-poza tym, że używam wywołania powłoki lub dwustronnej rury. W tym celu dostarczyłem Ci kompletny działający skrypt o nazwie ucsort że możesz zadzwonić, aby zrobić dokładnie to, co masz poproszony z łatwością.

Ten skrypt jest w 100% zgodny z pełnym algorytmem kompilacji Unicode, ze wszystkimi opcjami krawieckimi obsługiwanymi!! A jeśli masz zainstalowany opcjonalny moduł lub uruchamiasz Perl 5.13 lub lepszy, masz pełny dostęp do łatwych w użyciu ustawień regionalnych CLDR. Patrz poniżej.

Demonstracja

Wyobraź sobie zestaw wejściowy uporządkowany w ten sposób:

b o i j n l m å y e v s k h d f g t ö r x p z a ä c u q

Domyślne sortowanie według punktu kodu daje:

a b c d e f g h i j k l m n o p q r s t u v x y z ä å ö

Który jest niepoprawny przez Księga wszystkich. Korzystając z mojego skryptu, który używa algorytmu Unicode Collation, otrzymujesz następującą kolejność:

% perl ucsort /tmp/swedish_alphabet | fmt
a å ä b c d e f g h i j k l m n o ö p q r s t u v x y z

To jest domyślne sortowanie UCA. Aby uzyskać Szwedzkie locale, zadzwoń ucsort w ten sposób:

% perl ucsort --locale=sv /tmp/swedish_alphabet | fmt
a b c d e f g h i j k l m n o p q r s t u v x y z å ä ö

Oto lepsze demo wejściowe. Po pierwsze, zestaw wejściowy:

% fmt /tmp/swedish_set
cTD cDD Cöd Cbd cAD cCD cYD Cud cZD Cod cBD Cnd cQD cFD Ced Cfd cOD
cLD cXD Cid Cpd cID Cgd cVD cMD cÅD cGD Cqd Cäd cJD Cdd Ckd cÖD cÄD
Ctd Czd Cxd cHD cND cKD Cvd Chd Cyd cUD Cld Cmd cED Crd Cad Cåd Ccd
cRD cSD Csd Cjd cPD

Przez punkt kodowy, który sortuje w ten sposób:

Cad Cbd Ccd Cdd Ced Cfd Cgd Chd Cid Cjd Ckd Cld Cmd Cnd Cod Cpd Cqd
Crd Csd Ctd Cud Cvd Cxd Cyd Czd Cäd Cåd Cöd cAD cBD cCD cDD cED cFD
cGD cHD cID cJD cKD cLD cMD cND cOD cPD cQD cRD cSD cTD cUD cVD cXD
cYD cZD cÄD cÅD cÖD

Ale użycie domyślnego UCA sprawia, że jest to sortowane w ten sposób:

% ucsort /tmp/swedish_set | fmt
cAD Cad cÅD Cåd cÄD Cäd cBD Cbd cCD Ccd cDD Cdd cED Ced cFD Cfd cGD
Cgd cHD Chd cID Cid cJD Cjd cKD Ckd cLD Cld cMD Cmd cND Cnd cOD Cod
cÖD Cöd cPD Cpd cQD Cqd cRD Crd cSD Csd cTD Ctd cUD Cud cVD Cvd cXD
Cxd cYD Cyd cZD Czd

Ale w szwedzkim locale, to sposób:

% ucsort --locale=sv /tmp/swedish_set | fmt
cAD Cad cBD Cbd cCD Ccd cDD Cdd cED Ced cFD Cfd cGD Cgd cHD Chd cID
Cid cJD Cjd cKD Ckd cLD Cld cMD Cmd cND Cnd cOD Cod cPD Cpd cQD Cqd
cRD Crd cSD Csd cTD Ctd cUD Cud cVD Cvd cXD Cxd cYD Cyd cZD Czd cÅD
Cåd cÄD Cäd cÖD Cöd

Jeśli wolisz sortować wielkie litery przed małymi, zrób to:

% ucsort --upper-before-lower --locale=sv /tmp/swedish_set | fmt
Cad cAD Cbd cBD Ccd cCD Cdd cDD Ced cED Cfd cFD Cgd cGD Chd cHD Cid
cID Cjd cJD Ckd cKD Cld cLD Cmd cMD Cnd cND Cod cOD Cpd cPD Cqd cQD
Crd cRD Csd cSD Ctd cTD Cud cUD Cvd cVD Cxd cXD Cyd cYD Czd cZD Cåd
cÅD Cäd cÄD Cöd cÖD

Niestandardowe Sortowanie

Możesz zrobić wiele innych rzeczy z ucsort. Na przykład, oto jak sortować tytuły w języku angielskim:

% ucsort --preprocess='s/^(an?|the)\s+//i' /tmp/titles
Anathem
The Book of Skulls
A Civil Campaign
The Claw of the Conciliator
The Demolished Man
Dune
An Early Dawn
The Faded Sun: Kesrith
The Fall of Hyperion
A Feast for Crows
Flowers for Algernon
The Forbidden Tower
Foundation and Empire
Foundation’s Edge
The Goblin Reservation
The High Crusade
Jack of Shadows
The Man in the High Castle
The Ringworld Engineers
The Robots of Dawn
A Storm of Swords
Stranger in a Strange Land
There Will Be Time
The White Dragon

Do uruchomienia skryptu w ogóle potrzebny będzie Perl 5.10.1 lub lepszy. Aby uzyskać wsparcie lokalne, musisz zainstalować opcjonalny moduł CPAN Unicode::Collate::Locale. Alternatywnie można zainstalować wersje rozwojowe Perla, 5.13+, które obejmują ten moduł standardowo.

Wywołanie Konwenansów

Jest to szybki prototyp, więc ucsort jest głównie un(der)udokumentowane. Ale to jest jego podsumowanie tego, co przełącza / opcje akceptuje w linii poleceń:

    # standard options
    --help|?
    --man|m
    --debug|d

    # collator constructor options
    --backwards-levels=i
    --collation-level|level|l=i
    --katakana-before-hiragana
    --normalization|n=s
    --override-CJK=s
    --override-Hangul=s
    --preprocess|P=s
    --upper-before-lower|u
    --variable=s

    # program specific options
    --case-insensitive|insensitive|i
    --input-encoding|e=s
    --locale|L=s
    --paragraph|p
    --reverse-fields|last
    --reverse-output|r
    --right-to-left|reverse-input

Tak, ok: to jest naprawdę lista argumentów, których używam do wywołania Getopt::Long, ale masz pomysł. :)

Jeśli możesz dowiedzieć się, jak wywoływać Moduły biblioteki Perla z Pythona bezpośrednio bez wywoływania skryptu Perla, zrób więc. Sam Nie wiem jak. Chciałbym się nauczyć jak.

W międzyczasie, wierzę, że ten skrypt zrobi to, co trzeba zrobić w całej jego szczególności - i więcej! używam tego do sortowania tekstu. W końcu robi to, czego potrzebowałem od bardzo dawna.

Jedynym minusem jest to, że --locale argument powoduje spadek wydajności, chociaż jest wystarczająco szybki dla zwykłego, niestacjonarnego , ale nadal w 100% zgodny z UCA sortowanie. Ponieważ ładuje wszystko w pamięci, prawdopodobnie nie chcesz tego używać na dokumentach gigabajtowych. Używam go wiele razy dziennie i na pewno świetnie jest mieć w końcu zdrowe sortowanie tekstu.

 2
Author: tchrist,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-25 12:56:41

Aby go zaimplementować musisz przeczytać o " Unicode collation algorithm" Zobacz też http://en.wikipedia.org/wiki/Unicode_collation_algorithm

Http://www.unicode.org/unicode/reports/tr10/

Przykładowa implementacja jest tutaj

Http://jtauber.com/blog/2006/01/27/python_unicode_collation_algorithm/

 1
Author: Anurag Uniyal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-08 13:13:38

Ostatnio używam zope.ucol ( https://pypi.python.org/pypi/zope.ucol ) do tego zadania. Na przykład sortowanie języka niemieckiego ß:

>>> import zope.ucol
>>> collator = zope.ucol.Collator("de-de")
>>> mylist = [u"a", u'x', u'\u00DF']
>>> print mylist
[u'a', u'x', u'\xdf']
>>> print sorted(mylist, key=collator.key)
[u'a', u'\xdf', u'x']
Zope.ucol owija również ICU, więc byłaby alternatywą dla PyICU.
 1
Author: Brian Sutherland,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-10 11:08:14

Jeff Atwood napisał dobry post na naturalny porządek sortowania , w nim podlinkował do skryptu, który robi prawie to, o co prosisz.

To nie jest trywialny skrypt, w żaden sposób, ale robi sztuczkę.

 0
Author: Simon Scarfe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-08 13:11:58

Nie jest to kompletne rozwiązanie dla Twojego przypadku użycia, ale możesz rzucić okiem na unaccent.py skrypt z effbot.org. to, co w zasadzie robi, to usuwa wszystkie akcenty z tekstu. Możesz użyć tego "odkażonego" tekstu do sortowania alfabetycznego. (Dla lepszego opisu patrz ta strona.)

 0
Author: Mark van Lent,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-01-05 13:17:19