PythonでUnicode文字列をアルファベット順に並べ替える方法を教えてください。


97

Pythonはデフォルトでバイト値でソートします。これは、éがzおよびその他の同様に面白いものの後に来ることを意味します。Pythonでアルファベット順に並べ替える最良の方法は何ですか?

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

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


11
これはさらにロケールに依存することに注意してください:スウェーデン語では(あなたが言っているように) "Ä"は "Z"の後に続きますが、ドイツ語では "Ä"は通常 "AE"としてソートされます。
balpha 2009

@Georg:これで賞金を獲得した理由はありますか?locale.strcoll答えは、ユニコードは、ユーザーのロケールを使用してソートする必要があるときに正しいこと、そしてあなたがより多くのそれよりも(複数のロケールを使用して照合を)必要とするとき、あなたが欲しいものICUの答え。ほとんどの場合、あなたが欲しいlocale.strcoll
Glenn Maynard、

@Glenn:私はPython関数よりもうまくlocale.strcoll機能すること、特にICUが何をするのか知りたいと思っていました。基本的には、質問に対してもう少し注意が必要です。
GeorgSchölly、2011

1
@Georg:私の答えからわかるように、私は最近、Unicode照合アルゴリズムをいろいろと試しています。たとえば、--locale=de__phonebook必要なときに並べ替えることができるのは本当に素晴らしいことです。PerlモジュールはUCAテストスイートに合格します。私が提供したスクリプトにより、コマンドラインからのみ UCA全体とロケールを含むすべてのオプション簡単に操作できます。質問に答えないかもしれませんがそれでも非常に興味深いはずです。あなたがスイスにいるなら、私はあなたが柔軟性を使うことができると確信しています。:)
tchrist

回答:


75

IBMのICUライブラリはそれを行います(そしてそれ以上)。Pythonバインディング:PyICUがあります。

更新:ICU間の並べ替えの主な違いlocale.strcollは、ICU がISO 14651を使用しながら完全なUnicode照合アルゴリズムstrcoll使用することです

これら2つのアルゴリズムの違いは、ここに簡単に要約されています:http : //unicode.org/faq/collat​​ion.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 2とPython 3で同じように機能しますか?私はlocale.strxfrmu0b34a0f6aeによる回答から使用しましたが、それは機能するようで、はるかにエレガントで、追加のソフトウェアを必要としません。
2015年

私にとってはPython3では動作せず、sudo pip3 install PyICUインストールに失敗し、Python2でも動作します。
imrek

Pipからコンパイルしてインストールするには、pyICUにlibicu-devel.x86_64をインストールする必要がありました。機能しますが、最後の「sorted」コマンドの出力は次のとおりです:['a'、 '\ xc3 \ xa4'、 'b'、 'c']
Mike Stoddart

53

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

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


ちなみに1)UTF-8でエンコードされた `str 'の場合、locale.strxfrmが壊れているとは思いません。私はアプリケーションでベンチマークを行い、Unicodeオブジェクトでcmp = strcollを使用すると、すべてをUTF-8にデコードしてkey = strxfrmを使用するよりも安価であると結論しました
u0b34a0f6ae

6
ちなみに2)ロケールモジュールは、生成されたロケール(Linuxボックス用)でのみ機能し、任意のロケールでは機能しません。「ロケール-a」と教えてくれます
u0b34a0f6ae

6
@Georg:ロケールは単純なsubstring-> collat​​ing_elementマッピングのみをサポートしていると思います。展開(「ae」としてソートされるæ)、フランス語アクセントソート(文字は左から右にソートされますが、アクセントは右から左にソートされます)、再配置、およびおそらくいくつかのようなものは処理しません。詳細はこちら(完全なUCA機能セット):unicode.org/reports/tr10とここ(ロケール照合):chm.tu-dresden.de/edv/manuals/aix/files/aixfiles/LC_COLLATE.htm
ラファウDowgird

2
質問に明確に答えるには:はい、それタスク次第です。完全なUnicode照合アルゴリズムがより適切に処理するいくつかの特別なケースが明らかにありますが、可能性があることをすでに知らない限り、気づかないでしょう。
Lennart Regebro、2011

1
ここでの最大の問題は、アプリケーション全体に対してロケールをグローバルに設定する必要があることです。–比較のためだけに使用することはできません。
Robert Siemer 2015

9

James Tauberを試してみてください Python Unicode Collat​​ion Algorithmを。それはあなたが望むように正確にしないかもしれませんが、一見の価値があるようです。問題に関するもう少し詳しい情報については、クリストファー・レンツによるこの投稿を参照してください。


それは少なくとも一般的な問題を修正します。照合リストの言語依存バージョンも作成できると思います。
Lennart Regebro、2009

これではロケールを指定できず、参照設定ファイルはValueErrorを引き起こします。
thebjorn 2017

8

あなたはピューカにも興味があるかもしれません

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

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

この記事の執筆時点でオリジナルがダウンしていたため、スクリプトをgithubにアップロードし、それを取得するためにWebキャッシュを使用する必要がありました。

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

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


ピュカの+1。それはかなり速く(28000ワードをソートするのに3秒)、純粋なpythonであり、依存関係を必要としません。
マイケルマイヤー2013年

7

要約と詳細な回答:

locale.strcollPython 2ではlocale.strxfrm、問題のロケールがインストールされていると仮定して、実際に問題を解決し、適切に機能します。私もWindowsでテストしましたが、混乱を招くようにロケール名が異なりますが、一方で、サポートされているすべてのロケールがデフォルトでインストールされているようです。

ICU実際には、これは必ずしも上手くいくとは限りませんが、より多くのことを行います。特に、異なる言語のテキストを単語に分割できるスプリッターをサポートしています。これは、単語の区切りがない言語で非常に役立ちます。含まれていませんが、分割のベースとして使用する単語のコーパスが必要です。

ロケールの長い名前もあるので、ロケールのきれいな表示名、Gregorian以外のカレンダーのサポート(Pythonインターフェースでサポートされているかどうかはわかりません)、およびその他の多かれ少なかれあいまいなロケールサポートのトンを取得できます。 。

つまり、アルファベット順に並べ替え、ロケールに依存localeする場合は、特別な要件がないか、単語分割などのロケールに依存する機能がさらに必要でない限り、モジュールを使用できます。


6

私は答えはすでに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メソッドに渡すdictには、キーとしてUnicodeの序数(文字列ではない)があります。そのため、元のchar-to-charから再構築する必要がありspec_dictます。(翻訳するために渡すdictの値は、[序数でなければならないキーとは対照的に] Unicodeの序数、任意のUnicode文字列、または翻訳の一部として対応する文字を削除するNoneにすることができるため、「無視する」を指定するのは簡単ですソート目的の特定の文字」、「ソート目的でäをaeにマップ」など)。

Python 3では、「再構築」ステップをより簡単に行うことができます。例:

spec_dict = ''.maketrans(spec_dict)

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


この方法は便利ですが、azとbの間にáを配置することはできません
Barney


1

最近、私はこのタスクに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

完全なUCAソリューション

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

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

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

このスクリプトは、完全なUnicode照合アルゴリズムに 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
Foundations 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ですが、あなたはそのアイデアを理解しています。:)

Perlスクリプトを呼び出さずにPythonから直接Perlライブラリモジュールを呼び出す方法を理解できる場合は、必ずそうしてください。自分がどうなのかわからない。方法を学びたいです。

とりあえず、このスクリプトは、特に必要なことをすべて実行できると思います これをすべてのテキストの並べ替えに使用します。それは最終的に私は長い、長い時間のために必要だことありません。

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


2
いったいどうして、Pythonスクリプトがあるものを実行するためにPerlスクリプトを呼び出すのですか?
Lennart Regebro、2011

2
Pythonライブラリあることを知らなかったので、それが理由です。
tchrist

@Lennart:私は本当にネイティブライブラリ、または多くの場合C APIにリンクされて動的にロードされるライブラリを好みます(必要な場合があります)。さまざまなPyPerlおよびInline :: Perlソリューションが非常に説得力があるか、堅牢であるか、または柔軟であるかはわかりません。か何か。彼らはいくつかの理由で正しくないと感じています。私が最後にこれを試したのは、良い文字セット検出が必要なときでした(これは残念ながらありませんでした)。
tchrist

4
Python内でPerlを使用するのは中毒です。
Utku Zihnioglu

1
ワオ。うん-私にはPerlのように見えます、実際には2つ以上の方法があることがわかります:)しかし、PythonからCを呼び出すことは、一般に、Perlを呼び出すことによって追加される依存関係や実用的なサポートの問題を意味するわけではありません。この方法でそれを行うための多くの要求を見るのはひどく難しいです。
nealmcb 2011

0

それはあなたのユースケースのための完全なソリューションにはほど遠いですが、あなたは見てとることができunaccent.py effbot.orgからスクリプトを。基本的には、テキストからすべてのアクセントを削除します。その「サニタイズ」されたテキストを使用して、アルファベット順に並べ替えることができます。(詳細については、このページを参照しください。)


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.