我有一个未知(可变)长度的十六进制字符串,我想随时打包或解包以转换为字节。
["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'
如何从解包中获取大端十六进制值?
让我们收集一些事实。
首先,来自如何识别给定的十六进制字符串的字节序?:
“字节没有字节序。” – @MichaelPetch
–@VC.One
只有当你开始将字节串在一起时,你才会获得字节序。所以这不是这里的问题。
接下来,来自 ["string"].pack('H*') 是什么意思? :
[
] 将字符串解释为十六进制数字,每个字节两个字符,并将其转换为具有相应 ASCII 代码的字符的字符串。Array.pack
所以你的字符串
"a"
,作为一个字符,甚至没有描述一个完整的字节。
最后,来自 Array#pack 文档:
如果指定了
并且其容量足够,pack将其用作缓冲区并返回它。 …如果较短,则用“aBufferString
”填充间隙。\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 填充。