Unicode 文字列を単語や行として適切に分割する。
最新版は https://bitbucket.org/emptypage/uniseg-python から入手できます。
アーカイブを展開した後、コマンドラインから python setup.py install してください。
このモジュール(と Unicode)では、テキストの分割について次のような用語を使います。
unicode
オブジェクトPython の Unicode 文字列です。
その内部表現は Python インタプリタをビルドした条件によって異なり、narrow と wide とがあります。前者は Unicode 文字列を 16 ビット単位で、後者は 32 ビット単位でメモリに格納しています。
Unicode に収録される文字の数は 16 ビットの範囲を超えています。このため、narrow ビルドでは 16 ビットの範囲外の文字はふたつの 16 ビット表現を組み合わせて表現します(サロゲート・ペア)。narrow ビルドでは、文字列に格納されている文字の数と、unicode オブジェクトとしての長さ(len(s)
の値)が一致しないことがあります。たとえば U+20B9F は Python では u'\U00020b9f'
ですが、narrow ビルドでは len(u'\U00020b9f')
は 2
です。また list(u'\U00020b9f')
の結果は [u'\ud842', u'\udf9f']
になります。厳密には、narrow ビルドでは Unicode 文字列を一文字ずつ処理するのに list()
や for
文をそのまま使っては不適切なのです(それで問題ない処理が多いことも事実ですが)。
wide ビルドでは len(u'\U00020b9f')
は 1
であり、list(u'\U00020b9f')
の結果はそのまま [u'\U00020b9f']
になります。
自分の使っている Python インタプリタの Unicode 実装が narrow か wide かは sys.maxunicode
の値を見ればわかります。narrow ビルドではこの値が 16 ビットの最大値である 65535 になっています。wide ビルドではこれより大きい値が格納されています。
Python の unicode 文字列が上記のように実装によってその単位が異なる可能性があるのに対して、コード・ポイントというのは Unicode の文字セットに収録されている文字ひとつひとつに与えられている論理的な番号のことをいいます。コードポイントはふつう U+XXXX ないし U+XXXXX の形式で表記されます。
コードポイントは論理的な概念なので、Python の Unicode 実装に関わらず、Unicode の文字と一対一で対応しています。u'\U00020b9f'
は Python で len(u'\U00020b9f')
がいくつであろうと、コード・ポイントでいえば U+20B9F というひとつのコード・ポイントです。
Unicode 文字列の処理は、基本的にこのコード・ポイント単位になります。Unicode で「文字」といえば、単一のコード・ポイントを指すことがほとんどです。後述のグラフィム・クラスタとの混同を避けるために「文字」という言葉を使わずにこの「コード・ポイント」という用語をあえて使うこともあります。
wide ビルドの Python では、長さ 1 の unicode オブジェクトがすなわち 1 コード・ポイントに対応しています。
Unicode の「文字」といえばふつう単一のコード・ポイントのことですが、コンピュータの利用者にとってはひとつのコード・ポイントが必ずしもひとつの「文字」であるとは限りません。
たとえば、アイヌ語の表記につかわれる、小書きの「プ」に相当する文字があります。これは日本の規格である JIS X 0213 にはひとつの文字として他の文字と同様にひとつのコードが割り当てられていますが、Unicode ではこの文字を表す単一のコード・ポイントはありません。小書きの「フ」に相当する U+31F7 (KATAKANA LETTER SMALL HU) に U+309A (COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK) を続けて表します(個人的には、「プ」を小書きにするのと、小書きの「フ」に半濁点を付けるのとは等価でないような気がしますが、とにかくそういうことになっています)。しかし、テキストエディタなどの表示の上では、ユーザーはこれをひとつの「文字」と認識しています。デリート・キーによる削除や矢印キーによるカーソルの移動などでは、これらのコード・ポイントは一体のものとして扱われなければいけません。
このような「利用者にとっての一文字」の単位に相当するのが「グラフィム・クラスタ」です。エディタの文字数のカウント機能などでは、このグラフィム・クラスタの数を数える必要があります。
グラフィム・クラスタは言語によって解釈が異なる可能性があります。たとえば、チェコ語やスロバキア語ではアルファベットのひとつとして ‘ch’ を使います。
uniseg.TextWrapper
クラス折り返しエンジンの基底クラス。
uniseg.TTWrapper
クラス等幅フォントの折り返しエンジン。
uniseg.ord(c, index=None)
単一のコード・ポイントを表す Unicode 文字列 c に割り当てられた整数値を返す。組み込み関数 ord()
と同様だが、c がサロゲート・ペアで表わされる U+10000 以上の文字の時、narrow ビルド環境(len(c) == 2
)でも例外を起こさない。
index が指定されると、第 1 引数 c は単一の Unicode コードポイントではなく、それ以上の長さを持ちうる Unicode 文字列と解釈され、c[index]
に位置するコード・ポイントの値を返す。
uniseg.unichr(cp)
整数値 cp に相当するコード・ポイントを表す Unicode 文字列を返す。組み込み関数 unichr()
と同等だが、cp が 0x10000 以上でも例外を起こさない。
uniseg.code_point(s, index=0)
Unicode 文字列 s について、s[index]
の位置のコード・ポイント文字列を返す。単純に s[index]
の値を使うと、narrow ビルド環境ではサロゲート・ペアで表されている U+10000 以上のコード・ポイントを分断してしまうおそれがある。
index は省略すると 0 とみなされ、文字列先頭のコード・ポイントを返す。
uniseg.code_points(s)
Unicode 文字列 s に含まれているコード・ポイントを列挙する(イテレータ)。narrow ビルドの Python インタプリタでは、list(s)
はサロゲート・ペアで表現された U+10000 以上の文字をふたつの無効な文字に切り離してしまうが、この関数では適切に保たれる。
以下、説明が下っていくに従って、詳細でレイヤの低い処理になっていきます。基本的な処理であれば、「Unicode 文字列を分割する関数」「Unicode 文字列を分割する境界を取得する関数」のどちらかで十分なことも多いでしょう。
uniseg.grapheme_clusters(s, tailor=None)
Unicode 文字列 s を grapheme cluster 単位に分割して列挙する(イテレータ)。
uniseg.words(s, tailor=None)
Unicode 文字列 s を単語単位に分割して列挙する(イテレータ)。
uniseg.sentences(s, tailor=None)
Unicode 文字列 s を文単位に分割して列挙する(イテレータ)。
uniseg.line_break_units(s, legacy=False, tailor=None)
文字列 s を行分割可能な単位に分割して列挙する(イテレータ)。
legacy を True
にすると、旧来の文字コードでいわゆる全角文字として扱われていたギリシャ文字やキリル文字、一部の記号などを漢字と同等にみなし、これらの単語間での分割が許可されるようになります。
uniseg.grapheme_cluster_boundaries(s, tailor=None)
Unicode 文字列 s の grapheme cluster 境界のインデックスを列挙する(イテレータ)。0
から文字列末尾の境界(== len(s)
)まで。
uniseg.word_boundaries(s, tailor=None)
Unicode 文字列 s の単語境界のインデックスを列挙する(イテレータ)。0
から文字列末尾の境界(== len(s)
)まで。
uniseg.sentence_boundaries(s, tailor=None)
Unicode 文字列 s の文境界のインデックスを列挙する(イテレータ)。0
から文字列末尾の境界(== len(s)
)まで。
uniseg.line_break_boundaries(s, legacy=False, tailor=None)
行分割を行ってもよい境界のインデックスを列挙する(イテレータ)。0
から文字列末尾の境界(== len(s)
)まで。legacy の意味は line_break_breakables()
に同じ。
uniseg.grapheme_cluster_breakables(s)
Unicode 文字列 s のどこが grapheme cluster 境界として分割可能かを列挙する(イテレータ)。1 であれば分割可、0 であれば分割不可を表す。列挙する要素の数は len(s)
に等しい。
uniseg.word_breakables(s)
Unicode 文字列 s のどこが単語の境界として分割可能かを列挙する(イテレータ)。
uniseg.sentence_breakables(s)
Unicode 文字列 s のどこが文の境界として分割可能かを列挙する(イテレータ)。
uniseg.line_break_breakables(s, legacy=False)
Unicode 文字列 s のどこが行分割の境界として分割可能かを列挙する(イテレータ)。
boundaries(breakables)
breakables の情報を元に文字列の境界インデックスを列挙する(イテレータ)。境界は 0 から文字列末尾(== len(breakables))まで。列挙されるアイテムの数は、len(breakables) + 1
に等しい。
grapheme_cluster_boundaries(s)
は boundaries(grapheme_cluster_breakables(s))
と同等の処理にあたる。word_boundaries()
, sentence_boundaries()
, line_break_boundaries()
についても同様。
break_units(s, breakables)
breakables の情報を元に文字列 s を分割し、各部分文字列を列挙する(イテレータ)。
grapheme_clusters(s)
は break_units(grapheme_cluster_breakables(s))
と同等の処理にあたる。その他の words()
, sentences()
, line_break_units()
についても同様。
uniseg.grapheme_cluster(c, index=0)
Unicode 文字 c の Grapheme_Cluster クラスを文字列で返す。戻り値は次のうちのいずれか: 'Other'
, 'CR'
, 'LF'
, 'Control'
, 'Extend'
, 'Prepend'
, 'SpacingMark'
, 'L'
, 'V'
, 'T'
, 'LV'
, 'LVT'
index の意味は code_point()
関数に同じ。
uniseg.word_break(c, index=0)
Unicode 文字 c の Word_Break クラスを文字列で返す。戻り値は次のうちのいずれか: 'Other'
, 'CR'
, 'LF'
, 'Newline'
, 'Extend'
, 'format'
, 'Katakana'
, 'ALetter'
, 'MidNumLet'
, 'MidLetter'
, 'MidNum'
, 'Numeric'
, 'ExtendNumLet'
index の意味は code_point()
関数に同じ。
uniseg.sentence_break(c, index=0)
Unicode 文字 c の Sentence_Break クラスを文字列で返す。戻り値は次のうちのいずれか: 'CR'
, 'LF'
, 'Extend'
, 'Sep'
, 'Format'
, 'Sp'
, 'Lower'
, 'Upper'
, 'OLetter'
, 'Numeric'
, 'ATerm'
, 'SContinue'
, 'STerm'
, 'Close'
index の意味は code_point()
関数に同じ。
uniseg.line_break(c, index=0)
Unicode 文字 c の Line_Break クラスを文字列で返す。戻り値は次のうちのいずれか: 'BK'
, 'CR'
, 'LF'
, 'CM'
, 'NL'
, 'SG'
, 'WJ'
, 'ZW'
, 'GL'
, 'SP'
, 'B2'
, 'BA'
, 'BB'
, 'HY'
, 'CB'
, 'CL'
, 'CP'
, 'EX'
, 'IN'
, 'NS'
, 'OP'
, 'QU'
, 'IS'
, 'NU'
, 'PO'
, 'PR'
, 'SY'
, 'AI'
, 'AL'
, 'H2'
, 'H3'
, 'ID'
, 'JL'
, 'JV'
, 'JT'
, 'SA'
, 'XX'
index の意味は code_point()
関数に同じ。
本モジュールを使ったスクリプトを付属しています。いまのところサンプル・アプリケーション的な存在です。
unibreak.py
ファイルの文字列をコードポイント、文字(grapheme cluster)、単語、行分割単位で分割して一行ずつ出力します。
usage: unibreak.py [-h] [-e ENCODING] [-l] [-m {c,g,l,s,w}] [-o OUTPUT] [file] positional arguments: file input text file optional arguments: -h, --help show this help message and exit -e ENCODING, --encoding ENCODING text encoding of the input <cp932> -l, --legacy legacy mode (makes sense only with '--mode l') -m {c,g,l,s,w}, --mode {c,g,l,s,w} breaking algorithm <w> (c: code points, g: grapheme clusters, s: sentences l: line breaking units, w: words) -o OUTPUT, --output OUTPUT leave output to specified file
uniwrap.py
ファイルの文字列を指定された桁数で折り返し整形して出力します。漢字や仮名などはいわゆる全角文字としてアルファベットなどの倍の幅を持つものとして計算されます(早い話が日本語でも大丈夫ってことです)。
usage: uniwrap.py [-h] [-e ENCODING] [-x] [-j] [-r] [-t TAB_WIDTH] [-l] [-o OUTPUT] [-w WRAP_WIDTH] [-c] [file] positional arguments: file input file optional arguments: -h, --help show this help message and exit -e ENCODING, --encoding ENCODING file encoding <cp932> -x, --expand-tabs expand tabs to spaces -j, --justify justify lines -r, --ruler show ruler -t TAB_WIDTH, --tab-width TAB_WIDTH tab width <8> -l, --legacy treat ambiguous-width letters as wide -o OUTPUT, --output OUTPUT leave output to specified file -w WRAP_WIDTH, --wrap-width WRAP_WIDTH wrap width <60> -c, --char-wrap wrap on grapheme boundaries instead of line break boundaries
wxwrapdemo.py
プロポーショナルなフォントでの折り返し処理の例として、wxPython を使った GUI アプリケーションのサンプル・プログラムを同梱しています。
uniseg
に。TextWrapper
、TTWrapper
クラスをモジュール内に移動。あとでドキュメント化すること。wxwrapdemo.py
追加。breakables
でなく tailor
関数でカスタマイズを指定するようにした。あとでドキュメント化すること。*_boundaries
は 0 から列挙するようにした。*_breakables
追加。*_boundaries
および grapheme_clusters
, words
, sentences
, line_break_units
の結果をカスタマイズできるようにした。ord
関数に第 2 引数追加。以下の問題にたいして解決のめどが立ったらバージョン 1.0 にしたい。
TextWrapper
、TTWrapper
の仕様を整理。TextWrapper
、TTWrapper
、tailor
のカスタマイズ例をドキュメントに。MIT ライセンスです。
Copyright (c) 2012 Masaaki Shibata Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
(※ 上記条文は uniwrap.py による整形例です。-j -w 72 オプション。)
このページについてのご意見ご感想はゲストブックまたはメール <mshibata at emptypage.jp> まで。