使用字符串作为字节

Use string as bytes

我的问题如下:

我正在读取由某些软件生成的 .csv 并使用 Pandas 来读取它。 Pandas 正确读取 .csv,但其中一列存储表示向量的字节序列,Pandas 将它们存储为字符串。

所以我有 data(字符串),我想使用 np.frombuffer() 来获得正确的向量。问题是,data 是一个字符串,所以它已经编码,所以当我使用 .encode() 将它转换为字节时,序列不是原始序列。

示例:.csv 包含 \x00\x00,表示 dtype=np.uint8 的向量 [0,0]。 Pandas 将其存储为字符串,当我尝试处理它时,会发生如下情况:

data = df.data[x] # With x any row.
type(data)

print(data)

\x00\x00

e_data = data.encode("latin1")
print(e_data)

b'\\x00\\x00'

v = np.frombuffer(e_data, np.uint8)
print(v)

数组([ 92 120 48 48 92 120 48 48], dtype=uint8)

我只是想从数据中获取 b'\x00\x00' 而不是 b'\\x00\\x00' 我知道这是一个我还无法修复的编码混乱。

有什么办法吗?

谢谢!

问题:您(显然)有一个包含文字反斜杠转义序列的字符串,例如:

>>> x = r'\x00' # note the use of a raw string literal
>>> x # Python's representation of the string escapes the backslash
'\x00'
>>> print(x) # but it looks right when printing
\x00

据此,您希望创建一个相应的 bytes 对象,其中反斜杠转义序列被转换为相应的字节。

处理这些类型的转义序列是使用 unicode-escape 字符串编码完成的。您可能知道,字符串编码在 bytesstr 对象之间转换,指定字节序列对应于 Unicode 代码点的规则。

但是,unicode-escape 编解码器假定转义序列在等式的 bytes 一侧,而 str 一侧将具有相应的 Unicode 字符:

>>> rb'\x00'.decode('unicode-escape') # create a string with a NUL char
'\x00'

.encode 应用于字符串将反转该过程;所以如果你从反斜杠转义序列开始,它会重新转义反斜杠:

>>> r'\x00'.encode('unicode-escape') # the result contains two backslashes, represented as four
b'\\x00'
>>> list(r'\x00'.encode('unicode-escape')) # let's look at the numeric values of the bytes
[92, 92, 120, 48, 48]

如您所见,这显然不是我们想要的。

我们想从 bytes 转换为 str 以进行反斜杠转义。但是我们有一个 str 开始,所以我们需要将其更改为 bytes;我们想要 bytes 最后,所以我们需要更改从反斜杠转义中获得的 str 。在这两种情况下,我们都需要使每个 Unicode 代码点从 0-255 包含在内,对应于具有相同值的单个字节。

我们那个任务所需的编码称为latin-1,也称为iso-8859-1

例如:

>>> r'\x00'.encode('latin-1')
b'\x00'

因此,我们可以推断出整体转换:

>>> r'\x00'.encode('latin-1').decode('unicode-escape').encode('latin-1')
b'\x00'

根据需要:我们的 str 带有文字反斜杠、小写 x 和两个零,被转换为包含单个零字节的 bytes 对象。

或者:我们可以请求在解码时处理反斜杠转义,方法是使用codecs标准库模块中的escape_decode。然而,这个 isn't documented 并不是真的打算那样使用 - 它是用于实现 unicode-escape 编解码器和可能的其他一些东西的内部东西。

如果你想让自己暴露在未来崩溃的风险中,它看起来像:

>>> import codecs
>>> codecs.escape_decode(r'\x00\x00')
(b'\x00\x00', 8)

我们得到一个 2 元组,其中包含所需的 bytes,我假设是已解码的 Unicode 代码点的数量(即字符串的长度)。根据我的测试,它似乎只能对非反斜杠序列使用 UTF-8 编码(但这可能特定于 Python 的配置方式),并且您无法更改它;对于 decode 方法,没有实际参数来指定编码。就像我说的 - 不适合一般用途。


是的,所有这些看起来都很尴尬。您无法轻松获得对此类事情的支持的原因是,这并不是您真正打算设计系统的方式。从根本上说,所有数据都是字节;文本是由该字节数据编码的抽象。使用单个字节(值为 0)表示文本的四个字符(符号 \x00)不是正常编码,也不是一个可逆的(我怎么知道是将字节解码为这四个字符,还是解码为单个 NUL 字符?)。相反,您应该强烈考虑使用其他一些友好的数据字符串表示形式(可能是普通的十六进制转储)和一种与文本编码无关的方式来解析它。例如:

>>> data = '41 42' # a string in a simple hex dump format
>>> bytes.fromhex(data) # support is built-in, and works simply
b'AB'
>>> list(bytes.fromhex(data))
[65, 66]