Python 中 ISO-8859-2 和 UTF-8 之间的转换

Posted

技术标签:

【中文标题】Python 中 ISO-8859-2 和 UTF-8 之间的转换【英文标题】:Convertion between ISO-8859-2 and UTF-8 in Python 【发布时间】:2016-02-02 07:46:57 【问题描述】:

我想知道如何将 ISO-8859-2 (latin-2) 字符(我的意思是表示 ISO-8859-2 编码字符的整数或十六进制值)转换为 UTF-8 字符。

我需要在 python 中处理我的项目:

    从串口接收十六进制值,这些值是以 ISO-8859-2 编码的字符。 解码它们,这是 - 从中​​获取“标准”python unicode 字符串。 准备并写入 xml 文件。

使用 Python 3.4.3

txt_str = "ąęłóźć"
txt_str.decode('ISO-8859-2')
Traceback (most recent call last): File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute 'decode'

主要问题仍然是为“解码”方法准备有效输入(它适用于 python 2.7.10,这就是我在这个项目中使用的那个)。如何从十进制值中准备有效的字符串,即 Latin-2 代码数字?

请注意,由于我使用的设备和通信协议的限制,从串口接收 utf-8 字符会非常复杂。

样本数据,应要求提供:

68632057
62206A75
7A647261
B364206F
20616775
777A616E
616A2061
6A65696B
617A20B6
697A7970
6A65B361
70697020
77F36469
62202C79
6E647572
75206A65
7963696C
72656D75
6A616E20
73726F67
206A657A
65647572
77207972
73772065
00000069

这是一些示例数据。 ISO-8859-2 被推入 uint32,每个 int 4 个字符。

管理拆箱的代码:

l = l[7:].replace(",", "").replace(".", "").replace("\n","").replace("\r","") # crop string from uart, only data left
vl = [l[0:2], l[2:4], l[4:6], l[6:8]] # list of bytes
vl = vl[::-1] # reverse them - now in actual order

要从十六进制字符串中获取整数值,我可以简单地使用:

int_vals = [int(hs, 16) for hs in vl]

【问题讨论】:

它应该很简单:this_is_the_text_string.decode('ISO-8859-2'),它为您提供 unicode 字符串(至少在 Python 3 中)。 简单。从hex to bytes、decode as latin-2、encode as UTF-8 转换。你有任何样本数据吗? 但是,如果您要编写 XML,为什么不将值保留为 Unicode(从 ISO-8859-2 解码),并将其留给 XML 库编码为 UTF-8? 你应该看看这个。 http://***.com/questions/26125141/str-object-has-no-attribute-decode-in-python3 Python 3 中的字符串类型是 Unicode。如果要输入原始单字节,请使用 Python 3 字节字符串数据类型;但是您需要将字节编码为十六进制,而不是字符(因为这些是 Unicode 字符)。 【参考方案1】:

您的示例不起作用,因为您尝试使用 str 来保存字节。在 Python 3 中,您必须使用 byte 字符串。

实际上,如果您使用的是 PySerial,那么无论如何您都将读取字节字符串,您可以根据需要进行转换:

with serial.Serial('/dev/ttyS1', 19200, timeout=1) as ser:
    s = ser.read(10)
    # Py3: s == bytes
    # Py2.x: s == str
    my_unicode_string = s.decode('iso-8859-2')

如果您的 iso-8895-2 数据实际上随后被编码为字节的 ASCII 十六进制表示,那么您必须应用额外的编码层:

with serial.Serial('/dev/ttyS1', 19200, timeout=1) as ser:
    hex_repr = ser.read(10)
    # Py3: hex_repr == bytes
    # Py2.x: hex_repr == str

    # Decodes hex representation to bytes
    # Eg. b"A3" = b'\xa3'
    hex_decoded = codecs.decode(hex_repr, "hex") 
    my_unicode_string = hex_decoded.decode('iso-8859-2')

现在您可以将 my_unicode_string 传递给您最喜欢的 XML 库。

【讨论】:

感谢您的回答。我从 uart 收到的实际输入显示在第一篇文章中。我对此无能为力,这只是我可以从我的 uart 外围设备中读取的内容。我知道,这些字符的编码方式如下: 1. 每个字节([0:2],[2:4]...)都是十六进制数,代表 ISO-8859-2 字符。 2. 在每一行中,第一个字节是最后一个字节(LE/BE)。 3.“00”表示输入的字符串不能被4整除。 ISO-8859-2 没有字节顺序,因为每个字符只有 1 个字节,所以字符串也必须编码为 uint32 吗?也许您可以从远程共享一些代码,因为它根本不清楚 查看第一篇文章。遗憾的是,由于 IP 协议,我无法向您展示所有代码。【参考方案2】:

有趣的样本数据。理想情况下,您的示例数据应该是从 PySerial 接收的原始数据的直接打印。如果您实际上接收的是 8 位十六进制值的原始字节,那么:

#!python3
from binascii import unhexlify
data = b''.join(unhexlify(x)[::-1] for x in b'''\
68632057
62206A75
7A647261
B364206F
20616775
777A616E
616A2061
6A65696B
617A20B6
697A7970
6A65B361
70697020
77F36469
62202C79
6E647572
75206A65
7963696C
72656D75
6A616E20
73726F67
206A657A
65647572
77207972
73772065
00000069'''.splitlines())

print(data.decode('iso-8859-2'))

输出:

W chuj bardzo długa nazwa jakiejś zapyziałej pipidówy, brudnej ulicyumer najgorszej rudery we wsi

谷歌将波兰语翻译成英语:

The dick very long name some zapyziałej Small Town , dirty ulicyumer worst hovel in the village

【讨论】:

【参考方案3】:

此主题已关闭。工作代码,处理需要做的事情:

x=177
x.to_bytes(1, byteorder='big').decode("ISO-8859-2")

【讨论】:

如何解码给定的数据?你从 PySerial 获取字节,那么你是如何把它变成一个 int 的呢?

以上是关于Python 中 ISO-8859-2 和 UTF-8 之间的转换的主要内容,如果未能解决你的问题,请参考以下文章

DB2 代码从 Unicode 到 ISO8859-2 并返回

我有一个匈牙利文本 ISO-8859-2,我会将文本读入文件但在 Python3 中不起作用 [重复]

JSF ISO-8859-2 字符集

为 iso-8859-2 发送正确的字符集标头

Java 邮件字符集 ISO-8859-2 不起作用

Informix JDBC ISO-8859-2 编码问题