这是我打开、读取和输出的方式。该文件是用于 unicode 字符的 UTF-8 编码文件。我想打印前 10 个 UTF-8 字符,但下面代码片段的输出打印了 10 个奇怪的无法识别的字符。想知道是否有人知道如何正确打印?谢谢。
with open(name, 'r') as content_file:
content = content_file.read()
for i in range(10):
print content[i]
这10个怪异的角色每一个都是这样的,
�
问候, 林
最佳答案
当 Unicode 代码点(字符)被编码为 UTF-8 时,一些代码点被转换为单个字节,但许多代码点变成了多个字节。标准 7 位 ASCII 范围内的字符将被编码为单个字节,但更奇特的字符通常需要更多字节来编码。
所以你会得到那些奇怪的字符,因为你将那些多字节 UTF-8 序列分解为单个字节。有时这些字节将对应于正常的可打印字符,但通常它们不会,因此您得到的是 � 打印。
这是一个使用 ©、® 和 ™ 字符的简短演示,这些字符在 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
Stack Overflow 联合创始人 Joel Spolsky 写了一篇关于 Unicode 的好文章: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 编码字节字符串中提取单个字符的简短示例。正如我在评论中提到的,要正确执行此操作,您需要知道每个字符被编码为多少字节。
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 版本:
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
如果我们不知道 UTF-8 字符串中字符的字节宽度,那么我们需要做更多的工作。每个 UTF-8 序列在第一个字节中编码序列的宽度,如 the Wikipedia article on UTF-8 中所述。 .
以下 Python 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
通常,不需要做这种事情:只需使用提供的解码方法即可。
出于好奇,这里有一个 Python 3 版本的 get_width
,以及一个手动解码 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))
输出
©®™
© ® ™
关于python - 在 Python 2.7 中打印 UTF-8 字符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38651993/