このサイトについて

みんなのPython Webアプリ編 - 文字列と日本語処理

みんなのPython Webアプリ編 - 文字列と日本語処理

文字列と日本語処理

Pythonはバージョン2まで2種類の文字列型を持っていました。1つは文字列型、もう1つはユニコード型です。日本語のようなマルチバイト文字列をPythonで扱う場合には、ユニコード型を使う必要がありました。この仕様がいろいろなトラブルの元になっていたのですが,Python 3になって文字列型が統一され,日本語のように多くの文字を持つ言語を扱うプログラムを作りやすくなりました。

Pythonにはコデックス(codecs)と呼ばれる仕組みがあります。コデックスを使うと、ユニコードを中心にして他エンコードに変換ができます。文字列からEUC-JPなどの8ビット文字列への変換もできますし、逆にシフトJIS相当などの8ビット文字列から文字列への変換を行うこともできます。

また,Python 3からは,純粋な8ビット文字列を扱うための型としてbytes型が追加されました。この型は,Python 2の頃の文字列型と同じような機能を持っています。ファイルやインターネットから読み込んだ,エンコード情報を伴わない文字列データは,bytes型として扱います。8ビット文字列なので,バイト数が文字列の長さとなります。マルチバイト文字列を含むbytes型文字列は,エンコードに依存して期待したとおりの長さにならないことがあります。bytes型を文字列型に変換するためには,エンコード情報を添えて変換をする必要があります。

マルチバイト文字列の境界

Python 3の文字列型のひとつ利点は、文字の区切りを容易に扱えるということです。ASCII文字列でも日本語のマルチバイト文字列でも、1文字ずつ区切って扱うことができます。また,文字列もシーケンス型の一種ですので、インデックス指定やスライスを使って文字列の一部を取り出すことができます。以下に簡単な例を示します。

インデックスを使った文字列要素の取り出し

:::python
>>> s = "あいうabc"      # ユニコード文字列を変数に代入
>>> print(s[2])       # 3番目の文字を取り出す
う
>>> print(s[1:4])     # 2番目から4番目までの文字列を取り出す
いうa

同じことを、ユニコード相当のbytes型(8ビット文字列)で行うと,マルチバイト文字列の境界か正しく扱えず,いわゆる文字化けを起こしてしまいます。たとえば,変数sと同等のbytes型文字列の2番目に当たる文字列を取得しようとすると、バイト列で見たときの3番目の文字列となります。3バイト目は,ユニコードの内部表現「あ」のある文字コード130(16進数で82)に相当する文字列が返ってくるのです。

このように、8ビット文字列にインデックスを与えても、マルチバイト文字列の文字の区切りを正しく扱えないのです。bytes型のマルチバイト文字列を簡易に正しく扱いたい場合は、エンコード情報を与えて文字列型に変換するようにすると,プログラムが簡潔に書けます。

他のエンコードからユニコード文字列への変換

Webからの入力や、Eメールの本文やファイルから込み混んだ文字列などは,bytes型の文字列として取り込まれます。そのような場合には、エンコード情報を与えて文字列型に変換するようにします。

特定のエンコードを持ったbytes型の文字列からユニコード文字列に変換するには、以下のようにします。

unicode()関数の使用例:

:::python
s = b_str.decode('utf-8', 'replace')

bytes型の文字列b_strの「decode()」メソッドを使い,文字列型への変換を行います。第一引数には,文字列のエンコードを渡します。第2引数はオブションで、変換中に起こったエラーに対する対処を指定します。ここでは、変換不能な文字列があった場合には特定の文字列に置き換える(replace)ように指定しています。

文字列からbytes型への変換

encode()メソッドの使用例:

:::python
s = "あいう"
s.encode('euc-jp', 'ignore')

文字列を特定エンコードのバイト列に変換したい場合には、文字列に対してencode()メソッドを使います。メソッド呼び出しを行っているユニコード文字列が処理の対象になるので、第1引数は変換したいエンコード名となります。第2引数は、変換エラーが起こったときの対処を指示します。この例では、変換エラーが起こった場合も無視(ignore)して文字列をそのまま残すように指示しています。

プログラム内部での日本語の扱い

Python 3のプログラムでは、以下のように先頭でエンコードを指定するようにします。

:::html
# coding:utf-8

プログラム内部にマルチバイト文字列を埋め込むときは,文字列リテラルとして記述します。また,外部から取り込んだbytes文字列も,できるだけ文字列に変換するようにします。その上で,必要に応じてエンコードを変換するようにします。最近のWebアプリであれば,プログラム内部では文字列を使い、Webアプリケーションが出力を行う時にユニコード相当の文字列(UTF-8)に変換するとよいでしょう。

2015-01-20 18:37