Как отсортировать по алфавиту строки Unicode в Python?


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

есть ли библиотека для этого? Я ничего не смог найти. Предпочтительно сортировка должна иметь поддержку языка, поэтому он понимает, что åäö должен быть отсортирован после z на шведском языке, но что ü должен быть отсортирован по u и т. д. Таким образом, поддержка Unicode является в значительной степени требованием.

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

11 88

11 ответов:

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

обновление: основная разница в сортировке между ICU и locale.strcoll это то, что ICU использует полный Алгоритм Сортировки Юникода пока 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']

Я не вижу в ответах. Мое приложение сортируется в соответствии с языковым стандартом, используя стандартную библиотеку 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)

вопрос к Леннарту и другим ответчикам: неужели никто не знает "locale" или это не соответствует этой задаче?

попробуйте Джеймса Таубера Алгоритм Сортировки Юникода Python. Это может быть не совсем так, как вы хотите, но, кажется, стоит посмотреть. Дополнительные сведения о проблемах см. В разделе этот пост Кристофер Ленц.

вы также можете быть заинтересованы в pyuca:

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

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

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

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

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

краткий и развернутый ответ:

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

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

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

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

Я вижу, что ответы уже сделали отличную работу, просто хотел указать на одну неэффективность кодирования в Человеческого Рода. Для применения выборочного Чара на чара перевод в строку Unicode с используется код:

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-char spec_dict. (Значения в dict вы проходите переводить [в отличие от ключей, которые должны быть порядковые номера, могут быть в Юникоде порядковые номера, произвольные строки в Юникоде, или нет, чтобы удалить соответствующий символ как часть перевода, так это просто указать "игнорировать определенного характера для целей сортировки", "карта ä АЭ на сортировке", а любить.)

в Python 3 Вы можете получить шаг" перестройка " более просто, например:

spec_dict = ''.maketrans(spec_dict)

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

полное решение UCA

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

(вы можете не обязательно оценить это для шведского текста, но поскольку Perl использует абстрактные символы, вы можно использовать любую кодовую точку Unicode, которую вы хотите - независимо от платформы или сборки! Немногие языки предлагают такое удобство. Я упоминаю об этом, потому что в последнее время я много сражаюсь с Java за эту сумасшедшую проблему.)

проблема в том, что я не знаю, как получить доступ к модулю Perl из Python - apart, то есть с помощью выноски оболочки или двухсторонней трубы. С этой целью, поэтому я предоставил вам полный рабочий скрипт под названием ucsort что вы можете позвонить, чтобы сделать именно то, что вы попросили с совершенной легкостью.

этот скрипт на 100% соответствует полному Алгоритм Сортировки Юникода, со всеми вариантами пошива поддерживается!! И если у вас установлен дополнительный модуль или запущен Perl 5.13 или лучше, то у вас есть полный доступ к простым в использовании локалям CLDR. Увидеть ниже.

демонстрация

представьте, что входной набор упорядочен вот так:

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

Подгонянные Видов

вы можете сделать много других вещей с 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 или лучше запустить скрипт вообще. Для поддержки локали необходимо либо установить дополнительный модуль CPAN Unicode::Collate::Locale. Кроме того, вы можете установить версии разработки Perl, 5.13+, которые включают этот модуль стандартно.

Соглашения О Вызове

это быстрый прототип, так ucsort в основном документально подтверждена ООН(der). Но это его краткий обзор того, какие переключатели / параметры он принимает по команде линия:

    # 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, обязательно сделайте это. Я просто сам не знаю как. Я бы с удовольствием научился.

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

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

для его реализации вам нужно будет прочитать об " алгоритме сортировки Unicode" видеть http://en.wikipedia.org/wiki/Unicode_collation_algorithm

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

пример реализации здесь

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

в последнее время я использую zope.сайт ucol (https://pypi.python.org/pypi/zope.ucol) для этой задачи. Например, сортировка немецкого языка β:

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

Джефф Этвуд написал хороший пост на Естественный Порядок Сортировки, в нем он связан со скриптом, который делает в значительной степени то, что вы просите.

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

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