sue-sue's happy hacking

組込み系エンジニアのブログ

Pythonの日本語処理について

業務でPythonを使い始めて日本語の処理でとてもつまづいたのでそのメモと、ちょっとした作法を記載します。

str型とunicode

Pythonの文字列の型にstr型とunicode型がある。
なぜ2つ用意されているかは気が向いたときに調べます。
2つあるがゆえに気をつけないとないことがあります。

str型、もしくはunicode型の変数とlist型の変数の出力結果

>>> a = 'hello'
>>> print a
hello
>>> print type(a)
<type 'str'>

まず上記の変数の宣言の方法だと自然とstr型として文字列が変数aに格納されます。
では、日本語の文字列を格納するとどうでしょう。

>>> a = '焼肉'
>>> print a
焼肉
>>> print type(a)
<type 'str'>

となります。
では、unicode型で宣言する際はどうするかというと下記のようになります。

>>> a = u'焼肉'
>>> print a
焼肉
>>> print type(a)
<type 'unicode'>

上記の3つの実行結果を見るとstr型で宣言しようがunicode型で宣言しようが、特に困ることないんじゃないかと思ってしまいそうですね。

>>> a = ['hello', 'world', 'こんにちは', '世界']
>>> print type(a)
<type 'list'>
>>> print a
['hello', 'world', '\xe3\x81\x93\xe3\x82\x93\xe3\x81\xab\xe3\x81\xa1\xe3\x81\xaf', '\xe4\xb8\x96\xe7\x95\x8c']

とうとう出ましたね。
先ほどまで日本語の文字列を変数に代入して出力しても何も問題がありませんでしたが、とうとう問題発生しました。
色々この問題を調べてみたら次のことがわかりました。

  • str型、あるいはunicode型をprint()で出力する際は、print()が気を利かせて期待通りに出力してくれるらしいです。
  • list型をprint()で出力する際は、print()はlistの要素の型まで意識することができないらしいです。

引用元は忘却の彼方に行きました…次からは引用元も記載するように心がけます。

ちなみに先ほどのリスト型変数aの各要素の型は以下の通りです。

>>> for i in range(0, len(a)):
...     print type(a[i])
... 
<type 'str'>
<type 'str'>
<type 'str'>
<type 'str'>

では、もしリスト型変数aの全部の要素がstr型ではなくunicode型だったらどうなるでしょうか。

>>> a = [u'hello', u'world', u'こんにちは', u'世界']
>>> print a
[u'hello', u'world', u'\u3053\u3093\u306b\u3061\u306f', u'\u4e16\u754c']
>>> for i in range(0, len(a)):
...     print type(a[i])
... 
<type 'unicode'>
<type 'unicode'>
<type 'unicode'>
<type 'unicode'>

リスト型変数aの中身をunicode型にしても先ほど似た結果となってしまいました。
結論として、

  • 変数に文字列を格納するとstr型変数として生成される
  • unicode型変数を生成する際はu'こんにちは'のように、文字列の前にuを付けないといけない
  • str型、もしくはunicode型変数をprintするとprint()が気を利かせて日本語文字を出力してくれる
  • list型変数をprintすると日本語の文字列がバイトコードで出力されてしまう

基本的に処理で扱う文字列の型をunicode型として扱うべき

日本語文字列のパターンマッチ等、日本文字列をキャラクタとして扱う場合、unicode型が適切です。
理由は、インターネット上で公開されているPythonパッケージでは、パッケージ内での文字列をunicode型として扱うものがあるためです。
そのため、Pythonで文字列を扱う場合、unicode型で扱う方が便利だと言えます。

引用元:Pythonでの日本語処理:Unicode型と文字列型 - 思い立ったら書く日記(2016年10月9日)
http://d.hatena.ne.jp/kaito834/20090921/1253539430

decode()とencode()

str型→unicode型:str型変数.decode('utf-8')
unicode型→str型:uniode型変数.encode('shift-jis')
utf-8unicode
※shift-jisはstr型