Python在UTF-8中编码和解码的问题

时间:2017-09-10 17:05:53

标签: python unicode encoding utf-8 character-encoding

所以,我正在使用Python 3并且正在读取文件并将其作为字节分配给内存中的变量。 然后我将二进制数据转换为字符串:

def to_str(bytes_or_str):
  if isinstance(bytes_or_str, bytes):
    value = bytes_or_str.decode('utf-8', 'replace')
  else:
    value = bytes_or_str
  return value

我这样做的原因是因为我想用我制作的包含第一个256 chr()的列表来编辑和替换文件中的一些字符

编辑加载的文件变量后,我将文件重写为字节:

def to_bytes(bytes_or_str):
  if isinstance(bytes_or_str, str):
    value = bytes_or_str.encode('utf-8', 'replace')
  else:
    value = bytes_or_str
  return value

只要我只使用ASCII字符,效果很好。 我可以使用latin-1而不是utf-8,它可以使用多达256个字符,但之后 256编码和解码方法被破坏。 Latin-1是单字节,最多256个,我猜它是它工作到但不超过256的原因。 我想使用utf-8,因为它涵盖了更广泛的字符范围,但它失败了我的两种编码/解码方法,如果我使用非ASCII字符,数据会丢失。 我想知道这个问题是否是因为utf-8使用超过chr(128)或其他内容超过一个字节的事实?我想知道是否需要使用类似pack()方法的东西来使用多个字节来隔离字符? 使用此函数,我可以找到UTF-8中字符的字节数:

def utf8len(x):
return len(x.encode('utf-8'))

如果编码中的数据丢失错误是由每个字符多个字节引起的,那么我可以用某种方式使用它吗? 有没有其他想法?谢谢你的帮助。

另外:假设我将此字符'Ω'更改为字节,在python控制台中显示为:b'\ xe2 \ x84 \ xa6'。 如果每个字节的字节数是一组更多的字符,这究竟是如何工作的?当我将字符转换为字节时,Python将其显示为字符而不是0和1?不是字节0和1吗?我不知道Python在这里做了什么。

我制作了这段代码,试图解释它是如何工作的,但我仍然不完全理解:

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

def string2bits(s=''):
    return [bin(ord(x))[2:].zfill(8) for x in s]

def bits2string(b=None):
    return ''.join([chr(int(x, 2)) for x in b])

def utf8len(x):
    return len(x.encode('utf-8'))

def latin1len(x):
    return len(x.encode('latin-1'))

char_num = 255
def_char = chr(char_num)

char = def_char
bit = string2bits(char)
char2 = bits2string(bit)

print ('\nString:')
print (char2)

print( '\nUTF-8 byte Len:')
print(utf8len(char))
# I had to add this next if statement because:
#  LATIN-1 can't encode character '\u0100' in position 0: ordinal not in range(256)
if char_num < 256:
    print( '\nLatin-1 byte Len:')
    print(latin1len(char))

print ('\nList of Bits:')
for x in bit:
    print (x)

在上面#注释的代码开头,我可以更改utf-8和latin-1之间的脚本编码,还可以更改char_num变量,看看每个编码中该字符的位串是什么,但是如果latin-1的255以上我得到错误:UnicodeEncodeError:'latin-1'编解码器不能编码位置0的字符'\ u0100':序号不在范围内(256)

如果我使用:

将编码从utf-8硬编码到latin-1
#!/usr/bin/env python
# -*- coding: latin-1 -*-

这段代码不应该显示latin-1编码的def_char位吗? Python如何在这里工作?

2 个答案:

答案 0 :(得分:0)

我认为问题在于,在jpeg标题中存储的值可以包含任何字节值(例如像素密度,标记长度等)。

https://en.wikipedia.org/wiki/JPEG_File_Interchange_Format

在Latin-1中,每个字符都是一个字节,但不是每个字符都定义在0-255之间。

https://en.wikipedia.org/wiki/ISO/IEC_8859-1

但是,UTF-8是一种多字节编码。如果超过127,则第一个字节必须以110(对于2个字节的字符),1110(对于三个字节的字符)和11110(对于四个字节的字符)开始。第二个,第三个和第四个字节必须从10开始......

https://en.wikipedia.org/wiki/UTF-8

因此,如果您读取任意字节,则获取无效字节(序列)的概率很高,您可能通过读取jpeg标头来实现。因此,您可以获得Latin-1的有效字节,而不是UTF-8的有效字节。

答案 1 :(得分:0)

我想我应该更清楚。我在这里找到了答案:

https://stackoverflow.com/questions/3956935/storing-binary-data-in-utf-8-string