将位转换为字符串(数据)

时间:2016-01-02 21:22:25

标签: python-3.x

我的文件包含一些数据(从this PDF的“您将学习的内容”部分复制和粘贴的文本)。首先,我已成功将文件中的内容转换为位。但是,当我尝试将其转换回原始格式时,某些字符未正确转换,如下所示:

  

思科   开发了思科开放式网络环境(ONE)   架构作为一种多方面的网络方法   可编程性贯穿三大支柱:
  ??)É¥Í?н?? AA±¥2 N¥½¸ÁɽÉ?μμ¥¹?¥¹Ñ?É???我?¡A%̤?)?áÁ½Í??¥É3 N±ä½ ¸Íݥѡ????????????????????????????????????????????????????????????????????????????????????????????????????? ÷VäfÆ÷r6öçG&öÆÆW“æB÷VäfÆ÷r |vVçG0¨?HÝZ]HÙ??ÙXÝÈÈ[]?\ ?? \ X [Ý?\?^ \Ë?\ X [?Ù\?XÙ\Ë[ ?? \ UY \?UHU?Ú\ Y'] [U 2 O \ X?[] Y \ E [2 H 6] HU [

正如您在此处所见,某些字符已成功转换,而其他字符则未转换。

我的代码如下:

file = open("test.txt",'r')
myfile = ''.join(map(str,file))
l = []
for i in myfile:
  asc11 = ord(i)
  b = "{0:08b}".format(asc11)
  l.extend(int(y) for y in b)

string_bin = ''.join(map(str,l))
mydata = ''.join(chr(int(string_bin[i:i+8], 2)) for i in range(0,len(string_bin), 8))
print(mydata)

我的代码有什么问题?我需要改变什么才能使其正常工作?

1 个答案:

答案 0 :(得分:1)

发生了什么事?

您遇到编码问题,因为PDF中的某些字符是非ASCII字符。例如,项目符号点为U+2022,需要3 bytes of storage

当Python从您的文件中读取时,它不知道您用于编写该数据的编码。因此,它从文件中读取bytes并使用字符编码将它们转换为使用Python自己的内部unicode格式存储的str。 (这与Python 2不同,其中open()返回存储在str中的原始字节,然后您可以手动将其解码为unicode。)

因此,在Python 3中,open()接受一个名为encoding的参数。例如open("test.txt",'r', encoding='ascii')。由于您在致电open()时未指定编码,因此最终使用系统的默认编码。例如,在我的笔记本电脑上,默认编码为CP1252(LATIN-1)。你的可能会有所不同。

无论Python使用什么编码来解释您的文件,它都会在内部使用它自己的unicode格式来存储您的字符串。这意味着您的字符串可能在内部使用多字节字符,即使原始编码不是。例如,我的笔记本电脑使用CP1252将U+2022解释为•,其内部存储为U+00e2U+20ACU+00A2 - 为使用多字节字符存储,即使它只是原始文件中的一个字节。

假设您的计算机是理智的并且默认使用UTF-8(对于许多多字节字符,此解释类似)。当您到达项目符号点时,它将存储为U+2022。当您致电ord('\u2022')时,结果为8226。当您再致电"{0:08b}".format(8226)时,会返回"10000000100010"。那是一个 14个字符字符串。您的解析代码假定所有序数都会生成 8个字符字符串。因此,“二进制”输出变得不对齐。这意味着当你用8个字符的段解析二进制字符串时,它会被抛弃并开始将事物解释为控制字符和各种外语字符。

如果你调用open(..., encoding='ascii'),Python实际上会抛出异常,因为它会读取无效的ASCII字符。

可能的解决方案

我不确定为什么要将输入字符串转换为您正在使用的表示形式。这不是二元的,正如你的问题标题所暗示的那样。相反,您已将数据转换为其二进制编码的文本表示。

从技术上讲,当您将编码文本存储到文件时,它会使用二进制表示形式存储。 Python和任何文本编辑器必须先将这些字节解码为它的内部字符表示,然后才能将它们显示为文本。因此,调用open("test.txt", "r", encoding="utf-8")从文本文件中读取二进制数据并将其转换为Python的内部unicode格式。同样,调用myfile.encode('utf-8')将返回UTF-8编码的bytes,然后可以将其写入文件,网络套接字,

但是,如果您确实需要使用与当前使用的格式类似的格式,首先,我建议您在调用open()时指定编码(我建议使用UTF-8)。然后你可以考虑这些选项:

  1. 检测并省略非ASCII字符。他们将有一个序数> = 128。
  2. 模仿UTF-16或UTF-32并输出所有字符的多字节输出。例如,使用"{0:032b}".format(asc11)然后以32个字符的块解析结果。它的内存和存储效率低下,但它会保留多字节字符。
  3. 无论如何,我强烈建议您阅读Dive Into Python 3 chapter about strings