web-dev-qa-db-ja.com

PythonでUnicode文字列をアルファベット順にソートするにはどうすればよいですか?

Pythonはデフォルトでバイト値でソートします。つまり、éはzやその他の同様に面白いものの後にくるということです。 Pythonでアルファベット順にソートする最良の方法は何ですか?

このためのライブラリはありますか?何も見つかりませんでした。ソートには言語サポートが必要なので、スウェーデン語ではåäöをzの後にソートする必要があるが、üはuなどでソートする必要があることを理解する必要があります。

そのためのライブラリがない場合、これを行う最良の方法は何ですか?文字から整数値へのマッピングを行い、それで文字列を整数リストにマッピングするだけですか?

94
Lennart Regebro

IBMの [〜#〜] icu [〜#〜] ライブラリはそれを行います(さらに多くのことを行います)。 Pythonバインディング: PyIC

Update:ICUとlocale.strcollは、ICUは完全な nicode照合アルゴリズム を使用し、strcollISO 14651 を使用します。

これらの2つのアルゴリズムの違いをここに簡単に要約します: http://unicode.org/faq/collat​​ion.html#1 。これらはかなり特殊な特殊なケースであり、実際にはほとんど問題になりません。

>>> 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']
70
Rafał Dowgird

私は答えにこれを見ません。マイアプリケーションは、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)

レナートと他の回答者への質問:誰もが「ロケール」を知らないのですか、それともこのタスクに依存していないのですか?

52
u0b34a0f6ae

James Tauberの Python Unicode Collat​​ion Algorithm を試してください。期待どおりに動作しない場合がありますが、一見の価値があります。問題の詳細については、Christopher Lenzによる この投稿 を参照してください。

9
Vinay Sajip

pyucaにも興味があるかもしれません:

http://jtauber.com/blog/2006/01/27/python_unicode_collat​​ion_algorithm/

それは確かに最も正確な方法ではありませんが、少なくとも多少は正しくするための非常に簡単な方法です。また、ロケールはスレッドセーフではなく、プロセス全体で言語設定を設定するため、webappのロケールよりも優れています。また、外部Cライブラリに依存するPyICUよりもセットアップが簡単です。

この記事の執筆時点で元のスクリプトがダウンしていたため、スクリプトをgithubにアップロードしました。それを取得するには、Webキャッシュに頼らなければなりませんでした。

https://github.com/href/Python-Unicode-Collat​​ion-Algorithm

このスクリプトを使用して、ploneモジュールでドイツ語/フランス語/イタリア語のテキストを正常にソートしました。

8
href_

要約と拡張回答:

locale.strcoll under Python 2、およびlocale.strxfrmは実際に問題を解決し、問題のロケールがインストールされていると仮定して、良い仕事をします。ロケール名が紛らわしいほど異なるWindowsでもテストしましたが、一方で、サポートされているすべてのロケールがデフォルトでインストールされているようです。

ICUは、実際には必ずしもこれをうまく行うとは限りませんが、方法は同じですmore。最も顕著なのは、異なる言語のテキストを単語に分割できるスプリッターをサポートしていることです。これは、Wordの区切り文字を持たない言語に非常に役立ちます。ただし、分割のベースとして使用する単語のコーパスが必要です。これは含まれていないためです。

また、ロケールの長い名前があるため、ロケールのきれいな表示名、グレゴリオ暦以外のカレンダーのサポートを取得できます(ただし、Pythonインターフェイスがサポートしている)とトンとその他の多かれ少なかれ不明瞭なロケールのサポートのトン。

つまり、全体として:アルファベット順およびロケール依存でソートしたい場合は、特別な要件がない限り、またはロケール依存機能をさらに必要としない限り、localeモジュールを使用できます。単語スプリッター。

7
Lennart Regebro

Human Sort の1つのコーディングの非効率性を指摘したかっただけです。選択した文字単位の変換をUnicode文字列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-char spec_dict。 (翻訳するために渡す辞書の値は、キーではなく序数でなければなりません)Unicodeの序数、任意のUnicode文字列、または翻訳の一部として対応する文字を削除する[なし]を指定できます。並べ替え目的の特定の文字」、「並べ替え目的のäをaeにマッピングする」など)。

Python 3では、「再構築」ステップをより簡単に取得できます。例:

spec_dict = ''.maketrans(spec_dict)

このmaketrans静的メソッドをPython 3.で使用できる他の方法については、 ドキュメント を参照してください。

6
Alex Martelli

完全なUCAソリューション

これを行う最も簡単で、最も簡単で最も簡単な方法は、Perlライブラリモジュール、 nicode :: Collat​​e :: Locale を呼び出すことです。これは、標準のサブクラス nicode :: Collat​​e モジュール。必要なことは、コンストラクターにスウェーデンの"xv"のロケール値を渡すことだけです。

(スウェーデン語のテキストでは必ずしもこれを高く評価しないかもしれませんが、Perlは抽象文字を使用しているため、プラットフォームやビルドに関係なく、任意のUnicodeコードポイントを使用できます。このような便利さを提供する言語はほとんどありません。 Java最近この厄介な問題をめぐって多くのことで戦いに負けています。

問題は、Perlモジュールにアクセスする方法がわからないということですPython —別に、つまり、シェルコールアウトまたは両側パイプの使用。そのために、 したがって、ucsort と呼ばれる完全な作業スクリプトを提供しました。このスクリプトを呼び出すと、求めていることを完全に簡単に実行できます。

このスクリプトは、完全な nicode Collat​​ion Algorithmに完全に準拠しており、すべての調整オプションがサポートされています!!オプションのモジュールがインストールされているか、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 はほとんど文書化されていません。しかし、これはコマンドラインで受け入れるスイッチ/オプションの概要です。

    # 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の呼び出しに使用する引数リストですが、あなたはその考えを知っています。 :)

Pythonから直接Perlスクリプトを呼び出さずにPerlライブラリモジュールを呼び出す方法を理解できる場合は、必ずそうしてください。私は自分がどうすればよいかわかりません。どうやって。

それまでの間、このスクリプトは特に必要なことをすべて実行します—など!現在、すべてのテキストの並べ替えにこれを使用しています。それは最終的に私が長い間必要としていたことをします。

唯一の欠点は、--locale引数がパフォーマンスを低下させることです。ただし、通常の非ロケールには十分に高速ですが、100%UCAに準拠していますソート。メモリ内のすべてをロードするため、ギガバイトのドキュメントではおそらくこれを使用したくないでしょう。私は1日に何度も使用していますが、ようやくテキストの並べ替えが正常に行われるようになりました。

2
tchrist

これを実装するには、「Unicode照合アルゴリズム」について読む必要があります http://en.wikipedia.org/wiki/Unicode_collat​​ion_algorithm を参照してください

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

サンプル実装はこちら

http://jtauber.com/blog/2006/01/27/python_unicode_collat​​ion_algorithm/

1
Anurag Uniyal

最近、このタスクに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の代替となります。

1

ジェフ・アトウッドは Natural Sort Order に関する良い投稿を書きましたが、その中で彼は ほとんどあなたが尋ねるもの を行うスクリプトにリンクしました。

それは決して些細なスクリプトではありませんが、トリックを行います。

0
Simon Scarfe

ユースケースの完全なソリューションにはほど遠いですが、effbot.orgの naccent.py スクリプトをご覧ください。基本的には、テキストからすべてのアクセントを削除します。その「サニタイズ」テキストを使用して、アルファベット順にソートできます。 (より良い説明については this pageをご覧ください。)

0
Mark van Lent