Ruby 打包和解包十六进制值不返回相同的值?

问题描述 投票:0回答:1

我有一个未知(可变)长度的十六进制字符串,我想随时打包或解包以转换为字节。

["a"].pack("H*")
# => "\xA0"

我得到了

\xA0
——是因为它是小端字节序吗?我期待
\xA
\x0A

以同样的方式,如果再次解压,我也会得到

a0
十六进制字符串,即:

["a"].pack("H*").unpack("H*").first
=> "a0"

我又在期待

a
0a
,所以我有点困惑。这都一样吗?

我更喜欢十六进制字符串的大端字节序,但似乎

.pack
不接受
H
的字节序:

["a"].pack("H>*").unpack("H>*")
ArgumentError: '<' allowed only after types sSiIlLqQjJ (ArgumentError)
from <internal:pack>:8:in `pack'

如何从解包中获取大端十六进制值?

ruby hex byte endianness pack
1个回答
0
投票

让我们收集一些事实。


首先,来自如何识别给定的十六进制字符串的字节序?

“字节没有字节序。” – @MichaelPetch

–@VC.One

只有当你开始将字节串在一起时,你才会获得字节序。所以这不是这里的问题。


接下来,来自 ["string"].pack('H*') 是什么意思? :

[

Array.pack
] 将字符串解释为十六进制数字,每个字节两个字符,并将其转换为具有相应 ASCII 代码的字符的字符串。

所以你的字符串

"a"
,作为一个字符,甚至没有描述一个完整的字节。


最后,来自 Array#pack 文档

如果指定了

aBufferString
并且其容量足够,pack将其用作缓冲区并返回它。 …如果较短,则用“
\0
”填充间隙。

由于您的字符串太短而无法描述一个字节,因此在右侧用 0 填充。


将所有这些放在一起,很明显发生的事情是

Array.pack
在右侧填充了太短的字符串
"a"
,以便它可以完全使用它,并且所有内容都与字符串
 相关"a0"
从那里开始。

如果您对此不满意,您可以拉动的一个杠杆是将

H*
替换为
h*
,根据文档,这会将“高半字节优先”替换为“低半字节优先”。

以下是该更改的影响的说明:

["a0"].pack("H*") # => "\xA0"
["a0"].pack("h*") # => "\n"
["0a"].pack("H*") # => "\n"
["0a"].pack("h*") # => "\xA0"

["a0"].pack("H*").unpack("H*") # => ["a0"]
["a0"].pack("h*").unpack("h*") # => ["a0"]
["0a"].pack("H*").unpack("H*") # => ["0a"]
["0a"].pack("h*").unpack("h*") # => ["0a"]

当您询问字节序时,您想到的似乎是这种半字节排序,所以我希望这会有所帮助。但是,请注意,无论您选择哪种半字节顺序,1 个字符的字符串将始终用 right 填充零,而不是 left 填充。

© www.soinside.com 2019 - 2024. All rights reserved.