Python文字符号化の理解
6714 ワード
普通のプログラマーから優秀なプログラマーに進む途中、文字符号化は越えざるを得ないハードルであり、私たちのほとんどのプログラムは文字処理に関連しており、このハードルに越えられなければ、ほとんどいくつかの穴に直面する運命にある.本稿では,実際の例を用いて文字符号化復号化の過程を説明し,プログラムが文字をどのように処理しているのかをより明確に認識できるようにしようとする.本文に入る前に、まず文字セットと文字符号化の違いを理解する必要があります.Unicodeとは何か、UTF-8とは何か、GBKなどの基本概念を知る必要があります.もしあなたが理解していない場合は、次のいくつかの文章に進んでください.文字符号化の詳細な文字符号化ノートの後、プログラムが文字を処理する過程はどうなっているか考えてみましょう.最初は必ずエディタを開き、プログラムを書き出してソースファイル(Pythonでは.pyファイル)に保存すると思いますので、まずファイルの保存から始めましょう.
ソースファイルの保存
エディタに書かれたコードはすべて文字形式で存在しますが、これらの文字をハードディスクに格納するには、コンピュータが0/1シーケンスしか認識できないため、これらの文字はいくつかの符号化規則を通じてバイナリシーケンス列に変換し、ハードディスクに格納する必要があります.例えば次のプログラムを書きました
このファイルを格納する場合、GB 2312符号化で格納する場合、ファイルのバイナリ表現は、
ここで、73は
同様に、ここで73は
ソースファイルはすでにバイナリコードストリームでハードディスクに格納されていますが、ソースコードはどのように実行されますか?
ソース実行
ソースコードが実行されると、Python解釈器はまずソースファイルloadをメモリに入れ、1行でファイルの読み取りを開始し、実行を解釈します.
ただし、str文字列である場合、python解釈器はそのバイナリコードストリームのみを読み出すので、gb 2312 encodingfileを使用すると仮定する.pyでは、sが指す文字列
ただしLinuxまたはmacでは正しく実行できず、以下のように表示されます.
これは、Windows consoleのデフォルトはGBKコーデック(GB 2312の拡張)であるため、
もう1つのエピソードは、コードに漢字がある場合は、ファイルの先頭に符号化方式(#-*-coding:utf-8-または#coding=utf 8)を宣言する必要があります.そうしないと、解釈器はデフォルトでASCII符号化方式でソースファイルを開くので、次のようにエラーを報告します.
しかし、私たちの文字列がunicodeオブジェクトの文字列である場合、Python解釈器は文字列のバイトシーケンスを先に復号し、復号後のバイトシーケンスの参照をsに割り当て、utf 8 encodingfileを変更することができます.pyコードは次のとおりです.
保存後、hexdumpを使用してバイナリ符号化を表示します.
よく見ると、2つの
sが指すバイトシーケンスは
しかし、gb 2312 encodingfileを変更するとします.py、gb 2312符号化で保存し、このプログラムを実行して結果を見てみましょう.結果の直接エラー:
これは、Python解釈器が、gb 2312によって符号化されたバイトシーケンスを宣言されたutf−8符号化方式で復号しようとしたため、このようなエラーが発生したためである.
これでPythonがソースファイルをどのように読み書きするかが分かりましたが、Pythonが実行するときに外部ファイルをどのように読み書きするのでしょうか.
ファイルの読み書き
次に、次のコードを使用して文字列をファイルに書き込んでみます.ソースコードの保存にはutf-8を使用します.ファイル名はutf 8 encodingfile_です.write.py
macで実行します.結果は次のとおりです.
'ascii'codec can't encode characters in position 0-1:ordinal not in range(128)説明システムはファイルを書くときにASCIIを使って符号化しようとしていますが、utf-8を使うと宣言しているのに.
元のファイルヘッダ宣言はutf-8を使用していたが、解釈器がソースファイルを解釈する際に使用され、writeを呼び出してファイルを書くと、システムのデフォルトの符号化設定が呼び出されて符号化される.システムのデフォルトの符号化を見てみましょう.
やはり、システムのデフォルトはascii符号化方式です.この問題を解決するには2つの方法があり、1つはシステムのデフォルトの符号化方式を修正することであり、もう1つはopenのときに符号化方式を指定することであり、そのうち2つ目は明らかにより優雅である.
同様に、ファイルを読み込むときにcodecsを通過することもできます.Openは符号化方式を設定するが、まず、この読み込むファイルの符号化方式を知る必要があり、ファイルがutf-8で符号化されていると仮定すると、読み取るときは以下のようにすることができる.
また、ファイルから読み取るのではなく、標準以外の文字を直接使用する場合があります.これはdecodeを使用して先に復号する必要があります.
これでPythonコードについては終わりますが、収穫があれば、「いいね」を押してください.
ソースファイルの保存
エディタに書かれたコードはすべて文字形式で存在しますが、これらの文字をハードディスクに格納するには、コンピュータが0/1シーケンスしか認識できないため、これらの文字はいくつかの符号化規則を通じてバイナリシーケンス列に変換し、ハードディスクに格納する必要があります.例えば次のプログラムを書きました
s = ' '
print repr(s), s
このファイルを格納する場合、GB 2312符号化で格納する場合、ファイルのバイナリ表現は、
➜ testProgram hexdump -C gb2312encodingfile.py
00000000 73 20 3d 20 27 c4 e3 ba c3 27 0a 70 72 69 6e 74 |s = '....'.print|
00000010 20 72 65 70 72 28 73 29 2c 20 73 0a | repr(s), s.|
0000001c
ここで、73は
s
20は
3 dは=
27は'
c 4 e 3は
ba c 3は
を表している.utf-8を使用して同じコードを格納し、そのバイナリ表現がどのようになっているかを見てみましょう.➜ testProgram hexdump -C utf8encodingfile.py
00000000 73 20 3d 20 27 e4 bd a0 e5 a5 bd 27 0a 70 72 69 |s = '......'.pri|
00000010 6e 74 20 72 65 70 72 28 73 29 2c 20 73 0a |nt repr(s), s.|
0000001e
同様に、ここで73は
s
20は
3 dは=
27は'
を表すが、
は3バイトで表されるe 4 bd a 0は
e 5 a 5 bdは
を表すソースファイルはすでにバイナリコードストリームでハードディスクに格納されていますが、ソースコードはどのように実行されますか?
ソース実行
ソースコードが実行されると、Python解釈器はまずソースファイルloadをメモリに入れ、1行でファイルの読み取りを開始し、実行を解釈します.
ただし、str文字列である場合、python解釈器はそのバイナリコードストリームのみを読み出すので、gb 2312 encodingfileを使用すると仮定する.pyでは、sが指す文字列
がメモリに読み込まれた表現がc4 e3 ba c3
であり、print印刷を使用する場合、Windowsのconsole上で実行されると、正しく実行でき、以下のように表示される.➜ testProgram python gb2312encodingfile.py
'\xc4\xe3\xba\xc3'
ただしLinuxまたはmacでは正しく実行できず、以下のように表示されます.
➜ testProgram python gb2312encodingfile.py
'\xc4\xe3\xba\xc3' ���
これは、Windows consoleのデフォルトはGBKコーデック(GB 2312の拡張)であるため、
\xc4\xe3\xba\xc3
を漢字
として正しく復号表示することができるが、LinuxまたはMacではconsoleのデフォルトコーデック方式はUTF-8であるため、\xc4\xe3\xba\xc3
を正しく表示することはできない.もう1つのエピソードは、コードに漢字がある場合は、ファイルの先頭に符号化方式(#-*-coding:utf-8-または#coding=utf 8)を宣言する必要があります.そうしないと、解釈器はデフォルトでASCII符号化方式でソースファイルを開くので、次のようにエラーを報告します.
➜ testProgram python gb2312encodingfile.py
File "gb2312encodingfile.py", line 1
SyntaxError: Non-UTF-8 code starting with '\xc4' in file gb2312encodingfile.py on line 1, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details
しかし、私たちの文字列がunicodeオブジェクトの文字列である場合、Python解釈器は文字列のバイトシーケンスを先に復号し、復号後のバイトシーケンスの参照をsに割り当て、utf 8 encodingfileを変更することができます.pyコードは次のとおりです.
#-*- coding: utf-8 -*-
s = ' '
print repr(s), s
u = u' '
print repr(u), u
保存後、hexdumpを使用してバイナリ符号化を表示します.
➜ testProgram hexdump -C utf8encodingfile.py
00000000 23 2d 2a 2d 20 63 6f 64 69 6e 67 3a 20 75 74 66 |#-*- coding: utf|
00000010 2d 38 20 2d 2a 2d 0a 73 20 3d 20 27 e4 bd a0 e5 |-8 -*-.s = '....|
00000020 a5 bd 27 0a 70 72 69 6e 74 20 72 65 70 72 28 73 |..'.print repr(s|
00000030 29 2c 20 73 0a 0a 75 20 3d 20 75 27 e4 bd a0 e5 |), s..u = u'....|
00000040 a5 bd 27 0a 70 72 69 6e 74 20 72 65 70 72 28 75 |..'.print repr(u|
00000050 29 2c 20 75 0a |), u.|
00000055
よく見ると、2つの
文字列がe4 bd a0 e5 a5 bd
に符号化されmac上で実行され、結果は以下の通りである.➜ testProgram python utf8encodingfile.py
'\xe4\xbd\xa0\xe5\xa5\xbd'
u'\u4f60\u597d'
sが指すバイトシーケンスは
\xe4\xbd\xa0\xe5\xa5\xbd
であり、uが指すバイトシーケンスは\u4f60\u597d
であることがわかる(すなわち、e 4 bd a 0 e 5 a 5 bdをu 4 f 60u 597 dに復号化する)しかし、gb 2312 encodingfileを変更するとします.py、gb 2312符号化で保存し、このプログラムを実行して結果を見てみましょう.結果の直接エラー:
➜ testProgram python gb2312encodingfile.py
File "gb2312encodingfile.py", line 5
u = u'���'
SyntaxError: (unicode error) 'utf8' codec can't decode byte 0xc4 in position 0: invalid continuation byte
これは、Python解釈器が、gb 2312によって符号化されたバイトシーケンスを宣言されたutf−8符号化方式で復号しようとしたため、このようなエラーが発生したためである.
これでPythonがソースファイルをどのように読み書きするかが分かりましたが、Pythonが実行するときに外部ファイルをどのように読み書きするのでしょうか.
ファイルの読み書き
次に、次のコードを使用して文字列をファイルに書き込んでみます.ソースコードの保存にはutf-8を使用します.ファイル名はutf 8 encodingfile_です.write.py
#-*- coding: utf-8 -*-
s = ' '
with open('stroutput.txt', 'w') as f:
f.write(s)
u = u' '
with open('unicodeoutput.txt', 'w') as f:
f.write(u)
macで実行します.結果は次のとおりです.
➜ testProgram python utf8encodingfile_write.py
Traceback (most recent call last):
File "utf8encodingfile_write.py", line 8, in
f.write(u)
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
'ascii'codec can't encode characters in position 0-1:ordinal not in range(128)説明システムはファイルを書くときにASCIIを使って符号化しようとしていますが、utf-8を使うと宣言しているのに.
元のファイルヘッダ宣言はutf-8を使用していたが、解釈器がソースファイルを解釈する際に使用され、writeを呼び出してファイルを書くと、システムのデフォルトの符号化設定が呼び出されて符号化される.システムのデフォルトの符号化を見てみましょう.
>>> import sys
>>> sys.getdefaultencoding()
'ascii'
やはり、システムのデフォルトはascii符号化方式です.この問題を解決するには2つの方法があり、1つはシステムのデフォルトの符号化方式を修正することであり、もう1つはopenのときに符号化方式を指定することであり、そのうち2つ目は明らかにより優雅である.
# utf-8
import sys
reload(sys) # reload setdefaultencoding method
sys.setdefaultencoding('utf-8')
# codecs.open
import codecs
with codecs.open("filename", "w", encoding="utf-8") as f:
f.write(u)
同様に、ファイルを読み込むときにcodecsを通過することもできます.Openは符号化方式を設定するが、まず、この読み込むファイルの符号化方式を知る必要があり、ファイルがutf-8で符号化されていると仮定すると、読み取るときは以下のようにすることができる.
import codecs
with open("somefile", "r", encoding="utf-8") as f:
content = f.read()
また、ファイルから読み取るのではなく、標準以外の文字を直接使用する場合があります.これはdecodeを使用して先に復号する必要があります.
# if not decode, will raise exception: 'ascii' codec can't
# decode byte 0xe2 in position 0: ordinal not in range(128)
dash = '–'.decode("utf8")
if dash in title:
title = title.split(dash)[0]
これでPythonコードについては終わりますが、収穫があれば、「いいね」を押してください.