Unicodeのコードポイント(文字)はUTF-8、いくつかのコードポイントがあるとしてエンコードされています1バイトに変換されますが、多くのコードポイントは1バイト以上になります。標準の7ビットASCII範囲の文字は1バイトとしてエンコードされますが、よりエキゾチックな文字は一般にエンコードするためにより多くのバイトを必要とします。
これらのマルチバイトUTF-8シーケンスを1バイトに分割しているので、これらの奇妙な文字を取得しています。いつもそれらのバイトは通常の印字可能文字に対応しますが、しばしば印字されることはありません。
ここでは、UTF-8でそれぞれ2バイト、2バイト、3バイトにエンコードされた©、®、および™文字を使用した短いデモを紹介します。私の端末はUTF-8を使うように設定されています。
utfbytes = "\xc2\xa9 \xc2\xae \xe2\x84\xa2"
print utfbytes, len(utfbytes)
for b in utfbytes:
print b, repr(b)
uni = utfbytes.decode('utf-8')
print uni, len(uni)
出力
© ® ™ 9
� '\xc2'
� '\xa9'
' '
� '\xc2'
� '\xae'
' '
� '\xe2'
� '\x84'
� '\xa2'
© ® ™ 5
スタックオーバーフロー共同創設者、ジョエル・スポルスキは、ユニコードに良い記事を書いています:The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)
あなたはまた、中Unicode HOWTO記事を見てみる必要がありますPythonのドキュメント、Ned BatchelderのPragmatic Unicodeの記事「Unipain」
ここでは、UTF-8でエンコードされたバイト文字列から個々の文字を抽出する簡単な例を示します。コメントで言及したように、これを正しく行うには、各文字がエンコードされているバイト数を知る必要があります。私たちはUTFの文字のバイト幅がわからない場合
utfbytes = b"\xc2\xa9 \xc2\xae \xe2\x84\xa2"
widths = (2, 1, 2, 1, 3)
start = 0
for w in widths:
s = utfbytes[start:start+w]
print("%d %d [%s]" % (start, w, s.decode()))
start += w
:
utfbytes = "\xc2\xa9 \xc2\xae \xe2\x84\xa2"
widths = (2, 1, 2, 1, 3)
start = 0
for w in widths:
print "%d %d [%s]" % (start, w, utfbytes[start:start+w])
start += w
出力
0 2 [©]
2 1 [ ]
3 2 [®]
5 1 [ ]
6 3 [™]
FWIWは、ここではそのコードのPythonの3バージョンです-8文字列を入力すると、もう少し作業が必要になります。各UTF-8シーケンスは、the Wikipedia article on UTF-8で説明されているように、最初のバイトのシーケンスの幅をエンコードします。
次のPython 2のデモでは、幅情報をどのように抽出できるかを示しています。前の2つのスニペットと同じ出力を生成します。
# UTF-8 code widths
#width starting byte
#1 0xxxxxxx
#2 110xxxxx
#3 1110xxxx
#4 11110xxx
#C 10xxxxxx
def get_width(b):
if b <= '\x7f':
return 1
elif '\x80' <= b <= '\xbf':
#Continuation byte
raise ValueError('Bad alignment: %r is a continuation byte' % b)
elif '\xc0' <= b <= '\xdf':
return 2
elif '\xe0' <= b <= '\xef':
return 3
elif '\xf0' <= b <= '\xf7':
return 4
else:
raise ValueError('%r is not a single byte' % b)
utfbytes = b"\xc2\xa9 \xc2\xae \xe2\x84\xa2"
start = 0
while start < len(utfbytes):
b = utfbytes[start]
w = get_width(b)
s = utfbytes[start:start+w]
print "%d %d [%s]" % (start, w, s)
start += w
一般的には、は、この種のものを行うには必要はありません。ただ提供する復号方法を使用します。好奇心のために
、ここget_width
のPythonの3バージョン、およびUTF-8手動バイト文字列をデコードする機能です。
def get_width(b):
if b <= 0x7f:
return 1
elif 0x80 <= b <= 0xbf:
#Continuation byte
raise ValueError('Bad alignment: %r is a continuation byte' % b)
elif 0xc0 <= b <= 0xdf:
return 2
elif 0xe0 <= b <= 0xef:
return 3
elif 0xf0 <= b <= 0xf7:
return 4
else:
raise ValueError('%r is not a single byte' % b)
def decode_utf8(utfbytes):
start = 0
uni = []
while start < len(utfbytes):
b = utfbytes[start]
w = get_width(b)
if w == 1:
n = b
else:
n = b & (0x7f >> w)
for b in utfbytes[start+1:start+w]:
if not 0x80 <= b <= 0xbf:
raise ValueError('Not a continuation byte: %r' % b)
n <<= 6
n |= b & 0x3f
uni.append(chr(n))
start += w
return ''.join(uni)
utfbytes = b'\xc2\xa9 \xc2\xae \xe2\x84\xa2'
print(utfbytes.decode('utf8'))
print(decode_utf8(utfbytes))
出力
®©®©
™
™あなたのコンソールまたはTTYが同様の文字をサポートしている必要があり –
テキストファイルの内容を共有する - あなたは、端末の設定を変更する必要があるかもしれません。 – cdarke
@cdarke、ありがとうございました。私のコンソールは 'コンテンツを正しく印刷できました。これはUTF-8文字をサポートしているはずです。この問題は、 'content [i]'を印刷する場合にのみ発生します。あなたが思考を持っているなら、それは素晴らしいでしょう。 –