python3では、文字列とバイト列の区別が明確になりました。python2でバイナリデータを文字列で扱っていたり、strとunicodeの使い分けで混乱していたのがスッキリしたと思いますが、python2から移行するとちょっと混乱したりするのでまとめて置きます。
ちょっと語弊のある書き方かもしれませんが、ありがちな使われ方の例としてマトリックスを作成しました。
python3 | python2 | |
---|---|---|
byte列 | bytes (b'') |
str ('') |
通常の文字列 | str ('') |
str ('') |
unicode文字列 | str ('') |
unicode (u'') |
3では文字列はunicode文字列として扱われるようになったので、すべてpython2でいうところのu''
になりました。u''
表記してもエラーにはなりませんが(python3.3以上)同じ意味です。
バイナリデータを扱うときには、bytes型に変換します。bytes型は文字列っぽく扱えますが、strとbytesの連結などはできないので用途に合わせて適切な型で持つようにします。
例えば特定の文字コードの文字列を持ちたい場合はbytes型になります。str文字列として加工などをして最終的に出力する際に、任意の文字コードのバイト列としてエンコードして出力するという使い方になります。
strからbytes
encodeでbytes型(utf-8)に変換します。
>>> 'あいう'.encode('utf-8')
b'\xe3\x81\x82\xe3\x81\x84\xe3\x81\x86' #utf8のバイト列
UTF-8 bytesからstr
decodeで文字列に変換します。
>>>> b'\xe3\x81\x82\xe3\x81\x84\xe3\x81\x86'.decode('utf-8')
'あいう'
文字列のエンコードを意識した操作
たとえばファイルへShift_JISエンコードの文字列を出力したい場合、Python3においてはそれはbytes型のバイナリデータの出力という意味になります。
Python3の文字列は内部的にUnicodeで保持していますが、これをShift_JISにエンコードすることでbytes型のバイナリデータになります。(python2の時には、unicode文字列からstr文字列になっていました)
ShiftJISやEUCの文字列を正規表現で比較したい場合
Python3では、SJISやEUCの文字列はbytes型になってしまいますが、そのようなバイナリデータを正規表現でマッチングしたい場合にはどうすればよいでしょうか?
通常のマッチングであれば、decodeによってUnicode文字列に変換してから、Unicode文字列の世界でマッチングすれば問題ありません。
どうしてもSJISの文字コードの範囲などでマッチングしたい場合は、パターン文字列もbytes型で記述することで可能です。
>>> import re
# SJISにおける'ABCD'という全角文字列
>>> sjis_str = b'\x82\x60\x82\x61\x82\x62\x82\x63'
>>> sjis_str.decode('sjis')
'ABCD'
#bytes型文字列にstringのパターンは使用できない
>>> re.search(r'\x82\x61', sjis_str).group(0).decode('sjis')
TypeError: cannot use a string pattern on a bytes-like object
#パターン文字列もbytes型にする
>>> re.search(rb'\x82\x61', sjis_str).group(0).decode('sjis')
'A'
# ※上記はどうしてもsjisの文字コードで正規表現パターンを作りたかったため行ったもの。
# 単に'A'を探したいだけであれば、Unicode文字列に変換後にマッチングするほうが一般的。
>>> re.search(r'A', sjis_str.decode('sjis')).group(0)
'A'