103

Python はデフォルトでバイト値でソートします。これは、é が z の後に来ることを意味します。Pythonでアルファベット順にソートする最良の方法は何ですか?

これのためのライブラリはありますか?何も見つかりませんでした。できれば、並べ替えは言語サポートを備えている必要があります。これにより、スウェーデン語で åäö は z の後に並べ替える必要がありますが、ü は u などで並べ替える必要があることを理解できます。したがって、Unicode サポートはほぼ必須です。

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

4

11 に答える 11

80

IBM のICUライブラリーはそれを行います (さらに多くのことを行います)。Python バインディングがあります: PyICU

更新: ICU と のソートの主な違いlocale.strcollは、ICU が完全なUnicode 照合アルゴリズムstrcoll使用し、ISO 14651を使用することです。

これら 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']
于 2009-07-08T13:42:40.170 に答える
58

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

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

于 2009-08-23T14:32:43.377 に答える
9

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

于 2009-07-08T13:08:24.370 に答える
8

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 モジュールでドイツ語/フランス語/イタリア語のテキストを正常に並べ替えることができました。

于 2011-12-16T13:54:45.757 に答える
8

要約と拡張された回答:

locale.strcoll問題のロケールlocale.strxfrmがインストールされていると仮定すると、実際に問題を解決し、うまく機能します。Windowsでもテストしましたが、ロケール名が紛らわしいほど異なりますが、サポートされているすべてのロケールがデフォルトでインストールされているようです。

ICU実際には必ずしもこれがうまくいくとは限りませんが、より多くのことができます。最も注目すべきは、異なる言語のテキストを単語に分割できるスプリッターをサポートしていることです。これは、単語の区切りがない言語で非常に便利です。ただし、それは含まれていないため、分割のベースとして使用する単語のコーパスが必要です。

また、ロケールの長い名前があるため、ロケールのきれいな表示名、グレゴリオ暦以外のカレンダーのサポート (Python インターフェイスがそれをサポートしているかどうかはわかりませんが)、およびその他の多かれ少なかれあいまいなロケールのサポートを大量に取得できます。 .

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

于 2011-02-16T07:00:15.220 に答える
6

答えはすでに素晴らしい仕事をしているようですが、 HumanSortのコーディングの非効率性を指摘したかっただけです。選択的な文字ごとの変換を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)

メソッドに渡すdictにはtranslate、キーとしてUnicode序数(文字列ではない)が含まれているため、元のcharからcharへの再構築手順が必要ですspec_dict。([序数である必要があるキーとは対照的に]翻訳するために渡すdictの値は、Unicode序数、任意のUnicode文字列、または翻訳の一部として対応する文字を削除するNoneにすることができるため、「無視する」を指定するのは簡単です。ソート目的の特定の文字」、「ソート目的のaeにäをマップ」など)。

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

spec_dict = ''.maketrans(spec_dict)

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

于 2009-07-08T14:57:16.633 に答える
1

それを実装するには、「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/

于 2009-07-08T13:13:38.877 に答える
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
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たでしょうか。:)

Perl スクリプトを呼び出さずに Python から直接 Perl ライブラリ モジュールを呼び出す方法を理解できる場合は、ぜひそうしてください。私は自分自身の方法を知りません。方法を学びたいです。

それまでの間、このスクリプトは、特定のすべての作業で必要なことを実行できると信じています 私は今、これをすべてのテキストソートに使用しています。それはついに私が長い間必要としていたことをします。

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

于 2011-02-17T01:19:02.940 に答える
0

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

于 2009-07-08T15:18:03.053 に答える
0

Jeff Atwood は、Natural Sort Orderに関する優れた投稿を書きました。その中で、彼は、あなたが求めるほとんどのことを実行するスクリプトにリンクしています。

決して簡単なスクリプトではありませんが、うまく機能します。

于 2009-07-08T13:11:58.300 に答える