2019年1月3日木曜日

エンコーディングと文字列

エンコーディング

python2系のはなし。
プログラムファイル内の文字列をどの文字符号化方式(エンコーディング)としてデコードするかはファイルのヘッダ部で指定する。文字列を正しく扱うには、プログラムファイルの保存時に指定するエンコーディングとヘッダ部で指定するエンコーディングを一致させる必要がある。つまり、ファイル保存時の文字符号化方式が何かを処理系に教えるために使うのが、ヘッダ部のエンコーディング指定である。


encoding(cp932)

#! /usr/bin/env python
# -*- coding: cp932 -*-
encoding(utf-8)

#! /usr/bin/env python
# -*- coding: utf-8 -*-

windows環境ではデフォルトCP932で保存されるエディタが多く(?)、エンコーディングを気にせず保存するとCP932となる。この場合、ヘッダ部のエンコーディングはCP932にしないと実際の(ファイルの)エンコーディングと処理系に教えるエンコーディングが不一致となる。


文字列とユニコード文字列

やはりpython2系のはなし。
文字列型(str)とユニコード文字列型(unicode)の区別がある。
strをユニコードに変換することをデコード、逆をエンコードと呼ぶ。
違いは2つ(まだあるかもしれないが)。

  • 文字コードを扱う単位
  • ユニコードはIOへ出力する際自動で処理系に合わせてエンコードされる

'文字列'は文字列(str)型として扱われる。 これは、文字列がバイト列として扱われることを意味する。 例えば文字数を取得する際、バイト列で扱うと正しい文字数がカウントできない。 lenによるカウントはバイト列の数を返す。 printなどでIOに渡したとき、ヘッダで指定したエンコーディングでそのままIOに渡される。 処理系のエンコーディングとファイルのエンコーディングがあっていれば文字化けしないが、異なると文字化けする。

pythonにはユニコード文字列という型がある。 u'文字列'はユニコード文字列として扱われる。 これは、文字列がマルチバイトの集合として扱われることを意味する。 例えば文字数を取得する際、ユニコード文字列で扱うと正しい文字数がカウントできる。 lenによるカウントは文字数を返す。 printfなどでIOに渡したとき、自動で処理系に合わせてエンコードされるので文字化けしない。

cp932文字コード

A:41 #1バイト
ε:83C3 #2バイト
あ:82A0 #2バイト
utf-8文字コード

A:41 #1バイト
ε:ceb5 #2バイト
あ:e38182 #3バイト
cp932のプログラム

#! /usr/bin/env python
# -*- coding: cp932 -*-

if __name__ == '__main__':
    
    info = u'Aεあ'
    info2 = 'Aεあ'
    
    print info
    print len(info)
    print info2
    print len(info2)
    print info2.decode('cp932')
    print len(info2.decode('cp932'))
    print info2.decode('utf-8')
    print len(info2.decode('utf-8'))
cp932処理系での実行結果

Aεあ
3
Aεあ
5
Aεあ
3

Traceback (most recent call last):
  File "D:\learning\sample1.py", line 15, in 
    print info2.decode('utf-8')
  File "C:\Python27\lib\encodings\utf_8.py", line 16, in decode
    return codecs.utf_8_decode(input, errors, True)
UnicodeDecodeError: 'utf8' codec can't decode byte 0x83 in position 1: invalid start byte
>>> 

cp932の処理系でcp932のエンコーディングで書いたプログラムを実行した結果。

  • infoはユニコードなので3文字
  • info2はcp932のstrなので5文字
  • info2をデコードしたものはユニコードになるので3文字
  • 最後はinfo2(cp932)をutf-8でデコードできずエラー

utf-8のプログラム

#! /usr/bin/env python
# -*- coding: utf-8 -*-

if __name__ == '__main__':
    
    info = u'Aεあ'
    info2 = 'Aεあ'
    
    print info
    print len(info)
    print info2
    print len(info2)
    print info2.decode('utf-8')
    print len(info2.decode('utf-8'))
    print info2.decode('cp932')
    print len(info2.decode('cp932'))

cp932処理系での実行結果

Aεあ
3
Aホオ縺
6
Aεあ
3

Traceback (most recent call last):
  File "D:\learning\sample1.py", line 15, in 
    print info2.decode('cp932')
UnicodeDecodeError: 'cp932' codec can't decode byte 0x82 in position 5: incomplete multibyte sequence
>>> 

cp932の処理系でutf-8のエンコーディングで書いたプログラムを実行した結果。

  • infoはユニコードなので3文字
  • info2はutf-8なのでcp932の処理系では文字化けする
  • info2はutf-8のstrなので6文字
  • info2をデコードしたものはユニコードになるので3文字
  • 最後はinfo2(utf-8)をcp932でデコードできずエラー


0 件のコメント:

コメントを投稿