Вопрос по sorting, python, collation, internationalization, unicode – Как отсортировать строки Юникода в алфавитном порядке в Python?

93

Python сортирует по байтовым значениям по умолчанию, что означает & # xE9; приходит после z и других не менее забавных вещей. Каков наилучший способ сортировки по алфавиту в Python?

Есть ли библиотека для этого? Я ничего не смог найти. Предпочтительно сортировка должна иметь языковую поддержку, чтобы она понимала, что & # xE5; & # xE4; & # xF6; должно быть отсортировано после z на шведском языке, но это & # xFC; должны быть отсортированы по u и т. д. Поддержка Unicode, таким образом, является в значительной степени требованием.

Если для этого нет библиотеки, каков наилучший способ сделать это? Просто сделайте отображение из буквы в целочисленное значение и сопоставьте строку с целым списком с этим?

@ Георг: Была ли причина, по которой вы открыли награду за это?locale.strcoll ответ правильный, когда вам нужна сортировка Unicode с использованием языкового стандарта пользователя, и ICU отвечает на то, что вы хотите, когда вам нужно больше (сопоставление с использованием более чем одного языкового стандарта). Большую часть времени вы хотитеlocale.strcoll. Glenn Maynard
Обратите внимание, что это еще больше зависит от локали: на шведском (как вы заявляете) & quot; & # xC4; & quot; после "Z", но по-немецки "& # xC4;" обычно сортируется как «AE». balpha♦
@Glenn: я хотел знать, насколько хорошоlocale.strcoll работает и особенно чтоICU делает лучше, чем функция Python. В основном еще немного внимания к вопросу. Georg Schölly
@Georg: В последнее время я много играл с алгоритмом сортировки Unicode, как вы можете видеть из моего ответа. Это действительно здорово иметь возможность, например, сортировать по--locale=de__phonebook когда тебе это нужно. Модуль Perl проходит тестовый набор UCA, иthe script I provided значительно упрощает игру со всей УЦА, а также со всеми ее возможностямиincluding locales, просто из командной строки. Может не ответитьthe вопрос, но он все равно должен быть весьма интересным. Если вы находитесь в Швейцарии, я уверен, что вы могли бы использовать эту гибкость. :) tchrist

Ваш Ответ

11   ответов
2
A Complete UCA Solution

легкий и простой способ сделать это - вызвать модуль библиотеки Perl,Unicode :: Разобрать :: Locale, который является подклассом стандартаUnicode :: Разобрать модуль. Все, что вам нужно сделать, это передать конструктору значение локали"xv" для Швеции.

(Вы не обязательно должны ценить это для шведского текста, но поскольку в Perl используются абстрактные символы, вы можете использовать любой код Unicode, какой пожелаете, & # x2014; независимо от платформы или сборки! Мало языков предлагают такое удобство. x2019; в последнее время мы много сражаемся с Java из-за этой сводящей с ума проблемы.)

Проблема в том, что я не знаю, как получить доступ к модулю Perl из Python & # x2014; кроме того, от использования выноски оболочки или двусторонней трубы. С этой целью,Поэтому я предоставил вам полный рабочий сценарий под названиемucsort что вы можете позвонить, чтобы сделать именно то, что вы просили с полной легкостью.

This script is 100% compliant with the full Unicode Collation Algorithm, со всеми поддерживаемыми вариантами пошива !! А если у вас установлен дополнительный модуль или запущен Perl 5.13 или выше, то у вас есть полный доступ к простым в использовании языкам CLDR. Увидеть ниже.

Demonstration

Представьте, что входной набор упорядочен следующим образом:

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

Сортировка по умолчанию по кодовой точке дает:

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 ä å ö

что неверно в книге каждого. Используя мой скрипт, который использует алгоритм сортировки Unicode, вы получите следующий порядок:

% 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

Это сортировка UCA по умолчанию. Чтобы получить шведскую локаль, позвонитеucsort сюда:

% 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 å ä ö

Вот лучшее входное демо. Сначала входной набор:

% 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

По коду, это сортируется так:

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

Но использование UCA по умолчанию делает это следующим образом:

% 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

Но в шведском языке, таким образом:

% 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

Если вы предпочитаете сортировать заглавные буквы перед строчными, сделайте следующее:

% 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
Customized Sorts

Вы можете сделать много других вещей сucsort, Например, вот как сортировать заголовки на английском языке:

% 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

Вам понадобится Perl 5.10.1 или лучше, чтобы запустить скрипт в целом. Для поддержки локали вы должны либо установить дополнительный модуль CPANUnicode::Collate::Locale, Кроме того, вы можете установить версию для разработки Perl 5.13+, которая включает этот модуль стандартно.

Calling Conventions

Это быстрый прототип, поэтомуucsort в основном документировано. Но это его ОПИСАНИЕ того, какие переключатели / опции он принимает в командной строке:

    # 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

Да, хорошо: это действительно список аргументов, который я использую для вызоваGetopt::Long, Но ты получил идею. :)

Если вы можете понять, как вызывать модули библиотеки Perl из Python напрямую, не вызывая сценарий Perl, обязательно сделайте это. Я просто не знаю, как себя. Мне бы очень хотелось узнать, как это сделать.

Между тем, я считаю, что этот скрипт будет делать то, что вам нужно, во всех его специфических & # x2014;and more!  Теперь я использую это для всей сортировки текста. Этоfinally делает то, что мне нужно в течение долгого времени.

Единственным недостатком является то, что--locale Аргумент заставляет производительность снижаться, хотя это достаточно быстро для обычного, не локализованногоbut still 100% UCA compliant сортировка. Поскольку он загружает все в память, вы, вероятно, не хотите использовать это в гигабайтных документах. Я использую его много раз в день, и это, конечно, замечательно, если наконец-то появится нормальная сортировка текста.

Потому что я там не зналwas библиотека Python, вот почему!
Вот это да. Да, для меня это выглядит как Perl, на самом деле мы видим, что теперь есть более двух способов сделать что-то :) Но вызов C из Python обычно не подразумевает добавленных зависимостей и проблем практической поддержки, которые вызовет Perl, так что ужасно трудно увидеть, что нужно так поступать.
Другие ответы здесь указывают на два. :) Lennart Regebro
Использование Perl внутри Python - это просто зависимость.
С какой стати вы вызываете Perl-скрипт для чего-то, для чего существуют библиотеки Python? Lennart Regebro
69

ICU библиотека делает это (и многое другое). У него есть привязки Python:PyICU.

Update: Основное различие в сортировке между ICU иlocale.strcoll является то, что ICU использует полныйUnicode Collation Algorithm в то время какstrcoll использованияISO 14651.

Различия между этими двумя алгоритмами кратко изложены здесь:http://unicode.org/faq/collation.html#13, Это довольно экзотические особые случаи, которые редко имеют значение на практике.

>>> 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']
Мне пришлось установить libicu-devel.x86_64 для pyICU, чтобы скомпилировать и установить из Pip. Это работает, хотя вывод из последнего 'отсортированного' команда: ['a'; ', \ xc3 \ xa4', 'b', 'c']
Не работает с Python3 для меня,sudo pip3 install PyICU не удается установить, как и для Python2.
Это работает одинаково для Python 2 и Python 3? я использовалlocale.strxfrm Судя по ответу u0b34a0f6ae, он, кажется, работает и намного элегантнее и не требует дополнительного программного обеспечения.
0

Естественный порядок сортировки, в нем он связан со сценарием, который делаетв значительной степени то, что вы спрашиваете.

Это ни в коем случае не тривиальный сценарий, но он делает свое дело.

1
9

Python Unicode Collation Algorithm, Возможно, это не так, как вы хотите, но, кажется, стоит посмотреть. Для получения дополнительной информации о проблемах см.эта почта Кристофер Ленц.

Это не позволяет указать языковой стандарт, а эталонный файл конфигурации вызывает ошибку ValueError.
По крайней мере, это устраняет общую проблему. Я полагаю, что чувствительные к языку версии списка сортировки тоже могут быть созданы.
Мы используем это, чтобы эффективно повлиять на наш веб-сайт i18n.
8

pyuca:

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

Хотя это, конечно, не самый точный способ, это очень простой способ, по крайней мере, сделать это несколько правильно. Он также превосходит языковой стандарт в веб-приложении, так как языковой стандарт не является потокобезопасным и устанавливает языковые параметры для всего процесса. Его также проще настроить, чем PyICU, который использует внешнюю библиотеку C.

Я загрузил скрипт на github, так как оригинал был недоступен на момент написания этой статьи, и мне пришлось прибегнуть к веб-кешу, чтобы получить его:

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

Я успешно использовал этот скрипт для разумной сортировки немецкого / французского / итальянского текста в модуле plone.

+1 за пьюка. Он довольно быстрый (3 секунды для сортировки 28000 слов), чистый Python и не требует зависимости.
6

что ответы уже проделали отличную работу, просто хотел указать на одну неэффективность кодирования вСортировка человека, Для применения выборочного преобразования char-by-char к строке s в Юникоде используется код:

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

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

В Python есть гораздо лучший, быстрый и более лаконичный способ выполнения этой вспомогательной задачи (для строк Unicode - аналогичный метод для байтовых строк имеет другую и несколько менее полезную спецификацию! -):

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

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

Тираж, который вы передаетеtranslate Метод имеет порядковые номера Unicode (не строки) в качестве ключей, поэтому нам необходим этот шаг перестройки из исходного char-to-charspec_dict, (Значения в диктовке, которую вы передаете для перевода [в отличие от ключей, которые должны быть ординалами], могут быть ординалами Unicode, произвольными строками Unicode или None, чтобы удалить соответствующий символ как часть перевода, так что его легко указать » ; игнорировать определенный символ для целей сортировки "," сопоставить "с ae для целей сортировки" и т.п.).

В Python 3 вы можете получить & quot; перестроение & quot; шаг проще, например:

spec_dict = ''.maketrans(spec_dict)

Увидетьдокументы для других способов вы можете использовать этоmaketrans статический метод в Python 3.

51

локалью, используя стандартную библиотеку Python. Это довольно легко.

# 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)

Вопрос к Леннарту и другим ответчикам: «Кто-нибудь знает» язык? или это не до этой задачи?

Кстати 2) Модуль локали будет работать только с вашими сгенерированными локалями (для Linux-бокса), а не с любой произвольной локалью. & quot; locale -a & quot; скажу вам, какой
Самая большая проблема здесь: вы должны установить глобальную локаль для всего приложения. & # X2013; Вы не можете просто использовать его для сравнения.
Чтобы четко ответить на вопрос: да этоis до задачи. Очевидно, есть некоторые особые случаи, когда полный алгоритм сортировки Unicode обрабатывает лучше, но если вы уже не знали, что есть вероятность, что вы не заметите. Lennart Regebro
Кстати, я не думаю, что locale.strxfrm не работает для кодированных в UTF-8 `str '; Я протестировал приложение и пришел к выводу, что использование cmp = strcoll для объектов Unicode дешевле, чем декодирование всех в UTF-8 и использование key = strxfrm
@ Георг: я считаю, что локаль поддерживает только простое отображение подстроки -> collating_element. Он не обрабатывает такие вещи, как расширения (& # xE6; сортируется как & quot; ae & quot;), сортировка по французскому акценту (буквы сортируются слева направо, но акценты справа налево), перестановка и, возможно, некоторые другие. Подробности здесь (полный набор функций UCA):unicode.org/reports/tr10 и здесь (языковой стандарт сопоставления):chm.tu-dresden.de/edv/manuals/aix/files/aixfiles/LC_COLLATE.htm
7

locale.strcoll под Python 2, иlocale.strxfrm фактически решит проблему и сделает хорошую работу, предполагая, что у вас установлена соответствующая локаль. Я также проверил его под Windows, где названия локалей смешиваются, но, с другой стороны, кажется, что все поддерживаемые локали установлены по умолчанию.

ICU не обязательно делает это лучше на практике, однакоmore, В частности, он поддерживает разделители, которые могут разбивать тексты на разных языках на слова. Это очень полезно для языков, в которых нет разделителей слов. Вам нужно иметь набор слов, чтобы использовать их в качестве основы для разделения, потому что это не включено, однако.

Он также имеет длинные имена для локалей, так что вы можете получить красивые отображаемые имена для локали, поддержку других календарей, кроме григорианского (хотя я не уверен, что интерфейс Python поддерживает это) и тонны и тонны других более или менее неясных локалей поддерживает ,

So all in all: Если вы хотите сортировать по алфавиту и в зависимости от локали, вы можете использоватьlocale модуль, если у вас нет особых требований, или вам также нужны дополнительные функции, зависящие от локали, например, разделитель слов.

0

но вы могли бы взглянуть наunaccent.py скрипт от effbot.org. Что он в основном делает, это удаляет все акценты из текста. Вы можете использовать это «продезинфицированное»; текст сортировать по алфавиту. (Для лучшего описания см.этот стр.)

1

https://pypi.python.org/pypi/zope.ucol) для этой задачи. Например, сортировка по немецкому & # xDF ;:

>>> 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 также использует ICU, поэтому будет альтернативой PyICU.

Похожие вопросы