目录
当前位置: 首页 > 文档资料 > Ruby 参考手册 >

pack模板字符串

优质
小牛编辑
119浏览
2023-12-01

下面就是Array#pack、String#unpack中所用到的模板字符的一览表。模板字符后面可以跟上表示"长度"的数字。若使用'*'来取代"长度"的话, 则表示"剩下的所有字符"之意。

长度的定义因模板字符的不同而有所差异, 大体上像

"iiii"

这样的连续字符可以写成

"i4"

这个样子。

在下面的说明中, short和long分别表示长度为2和4字节的数值(也就是通常32位机器所指的short和long的大小), 这与具体的系统无关。 若`s', `S', `l', `L'后面出现`_'或`!'(如"s!")的话, 则表示这个short或long的大小取决于具体的系统。

请注意: `i', `I' (int)的大小总是取决于系统的, 而`n', `N', `v', `V'的大小则是系统无关的(不能添加`!')。

模板字符串中的空格会被忽略。 ruby 1.7 特性: 另外,从`#'开始到换行处或者到模板字符串结尾之间的部分会被看做是注释。

在下面的说明中, 若针对某问题Array#pack和String#unpack有不同的解释时, 就使用/将两者分开, 即采用 "Array#pack的说明部分/String#unpack的说明部分" 的形式加以说明.

  • a

    ASCII字符串(塞入null字符/保留后续的null字符或空格)

    ["abc"].pack("a") => "a"
    ["abc"].pack("a*") => "abc"
    ["abc"].pack("a4") => "abc\0"
    "abc\0".unpack("a4") => ["abc\0"]
    "abc ".unpack("a4") => ["abc "]
    
  • A

    ASCII字符串(塞入空格/删除后续的null字符和空格)

    ["abc"].pack("A") => "a"
    ["abc"].pack("A*") => "abc"
    ["abc"].pack("A4") => "abc "
    "abc ".unpack("A4") => ["abc"]
    "abc\0".unpack("A4") => ["abc"]
    
  • Z

    null终点字符串(与a相同 / 删除后续的null字符)

    ["abc"].pack("Z") => "a"
    ["abc"].pack("Z*") => "abc"
    ["abc"].pack("Z4") => "abc\0"
    "abc\0".unpack("Z4") => ["abc"]
    "abc ".unpack("Z4") => ["abc "]
    
  • b

    位串(从下级位到上级位)

    "\001\002".unpack("b*") => ["1000000001000000"]
    "\001\002".unpack("b3") => ["100"]
    ["1000000001000000"].pack("b*") => "\001\002"
    
  • B

    位串(从上级位到下级位)

    "\001\002".unpack("B*") => ["0000000100000010"]
    "\001\002".unpack("B9") => ["000000010"]
    ["0000000100000010"].pack("B*") => "\001\002"
    
  • h

    16进制字符串(下级半字节(nibble)在先)

    "\x01\xfe".unpack("h*") => ["10ef"]
    "\x01\xfe".unpack("h3") => ["10e"]
    ["10ef"].pack("h*") => "\001\376"
    
  • H

    16进制字符串(上级半字节在先)

    "\x01\xfe".unpack("H*") => ["01fe"]
    "\x01\xfe".unpack("H3") => ["01f"]
    ["01fe"].pack("H*") => "\001\376"
    
  • c

    char (8bit 有符号整数)

    "\001\376".unpack("c*") => [1, -2]
    [1, -2].pack("c*") => "\001\376"
    [1, 254].pack("c*") => "\001\376"
    
  • C

    unsigned char (8bit 无符号整数)

    "\001\376".unpack("C*") => [1, 254]
    [1, -2].pack("C*") => "\001\376"
    [1, 254].pack("C*") => "\001\376"
    
  • s

    short (16bit 有符号整数, 取决于Endian) (s! 并非16bit, 它取决于short的大小)

    小Endian:

    "\001\002\376\375".unpack("s*") => [513, -514]
    [513, 65022].pack("s*") => "\001\002\376\375"
    [513, -514].pack("s*") => "\001\002\376\375"
    

    大Endian:

    "\001\002\376\375".unpack("s*") => [258, -259]
    [258, 65277].pack("s*") => "\001\002\376\375"
    [258, -259].pack("s*") => "\001\002\376\375"
    
  • S

    unsigned short (16bit 无符号整数, 取决于Endian) (S!并非16bit,它取决于short 的大小)

    小Endian:

    "\001\002\376\375".unpack("S*") => [513, 65022]
    [513, 65022].pack("s*") => "\001\002\376\375"
    [513, -514].pack("s*") => "\001\002\376\375"
    

    大Endian:

    "\001\002\376\375".unpack("S*") => [258, 65277]
    [258, 65277].pack("S*") => "\001\002\376\375"
    [258, -259].pack("S*") => "\001\002\376\375"
    
  • i

    int (有符号整数, 取决于Endian和int的大小)

    小Endian, 32bit int:

    "\001\002\003\004\377\376\375\374".unpack("i*") => [67305985, -50462977]
    [67305985, 4244504319].pack("i*") => RangeError
    [67305985, -50462977].pack("i*") => "\001\002\003\004\377\376\375\374"
    

    大Endian, 32bit int:

    "\001\002\003\004\377\376\375\374".unpack("i*") => [16909060, -66052]
    [16909060, 4294901244].pack("i*") => RangeError
    [16909060, -66052].pack("i*") => "\001\002\003\004\377\376\375\374"
    
  • I

    unsigned int (无符号整数, 取决于Endian和int的大小)

    小Endian, 32bit int:

    "\001\002\003\004\377\376\375\374".unpack("I*") => [67305985, 4244504319]
    [67305985, 4244504319].pack("I*") => "\001\002\003\004\377\376\375\374"
    [67305985, -50462977].pack("I*") => "\001\002\003\004\377\376\375\374"
    

    大Endian, 32bit int:

    "\001\002\003\004\377\376\375\374".unpack("I*") => [16909060, 4294901244]
    [16909060, 4294901244].pack("I*") => "\001\002\003\004\377\376\375\374"
    [16909060, -66052].pack("I*") => "\001\002\003\004\377\376\375\374"
    
  • l

    long (32bit 有符号整数, 取决于Endian) (l! 并非32bit, 它取决于long的大小)

    小Endian, 32bit long:

    "\001\002\003\004\377\376\375\374".unpack("l*") => [67305985, -50462977]
    [67305985, 4244504319].pack("l*") => RangeError
    [67305985, -50462977].pack("l*") => "\001\002\003\004\377\376\375\374"
    
  • L

    unsigned long (32bit 无符号整数, 取决于Endian) (L! 并非32bit, 它取决于long的大小)

    小Endian, 32bit long:

    "\001\002\003\004\377\376\375\374".unpack("L*") => [67305985, 4244504319]
    [67305985, 4244504319].pack("L*") => "\001\002\003\004\377\376\375\374"
    [67305985, -50462977].pack("L*") => "\001\002\003\004\377\376\375\374"
    
  • q

    ruby 1.7 特性: long long (有符号整数, 取决于Endian和long long 的大小) (在C中无法处理long long时, 就是64bit)

    小Endian, 64bit long long:

    "\001\002\003\004\005\006\007\010\377\376\375\374\373\372\371\370".unpack("q*")
    => [578437695752307201, -506097522914230529]
    [578437695752307201, -506097522914230529].pack("q*")
    => "\001\002\003\004\005\006\a\010\377\376\375\374\373\372\371\370"
    [578437695752307201, 17940646550795321087].pack("q*")
    => "\001\002\003\004\005\006\a\010\377\376\375\374\373\372\371\370"
    
  • Q

    ruby 1.7 特性: unsigned long long (无符号整数, 取决于Endian和 long long 的大小) (在C中无法处理long long时, 就是64bit)

    小Endian, 64bit long long:

    "\001\002\003\004\005\006\007\010\377\376\375\374\373\372\371\370".unpack("Q*")
    => [578437695752307201, 17940646550795321087]
    [578437695752307201, 17940646550795321087].pack("Q*")
    => "\001\002\003\004\005\006\a\010\377\376\375\374\373\372\371\370"
    [578437695752307201, -506097522914230529].pack("Q*")
    => "\001\002\003\004\005\006\a\010\377\376\375\374\373\372\371\370"
    
  • m

    被base64编码过的字符串。每隔60个八位组(或在结尾)添加一个换行代码。

    Base64是一种编码方法, 它只使用ASCII码中的65个字符(包括[A-Za-z0-9+/]这64字符和用来padding的'='),将3个八位组(8bits * 3 = 24bits)中的二进制代码转为4个(6bits * 4 = 24bits)可印刷的字符。具体细节请参考RFC2045。

    [""].pack("m") => ""
    ["\0"].pack("m") => "AA==\n"
    ["\0\0"].pack("m") => "AAA=\n"
    ["\0\0\0"].pack("m") => "AAAA\n"
    ["\377"].pack("m") => "/w==\n"
    ["\377\377"].pack("m") => "//8=\n"
    ["\377\377\377"].pack("m") => "////\n"
    ["abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"].pack("m")
    => "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJT\nVFVWV1hZWg==\n"
    ["abcdefghijklmnopqrstuvwxyz"].pack("m3")
    => "YWJj\nZGVm\nZ2hp\namts\nbW5v\ncHFy\nc3R1\ndnd4\neXo=\n"
    "".unpack("m") => [""]
    "AA==\n".unpack("m") => ["\000"]
    "AA==".unpack("m") => ["\000"]
    "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJT\nVFVWV1hZWg==\n".unpack("m")
    => ["abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"]
    "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWg==\n".unpack("m")
    => ["abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"]
    
  • M

    经过quoted-printable encoding编码的字符串

    ["a b c\td \ne"].pack("M") => "a b c\td =\n\ne=\n"
    "a b c\td =\n\ne=\n".unpack("M") => ["a b c\td \ne"]
    
  • n

    网络字节顺序(大Endian)的unsigned short (16bit 无符号整数)

    [0,1,-1,32767,-32768,65535].pack("n*")
    => "\000\000\000\001\377\377\177\377\200\000\377\377"
    "\000\000\000\001\377\377\177\377\200\000\377\377".unpack("n*")
    => [0, 1, 65535, 32767, 32768, 65535]
    
  • N

    网络字节顺序(大Endian)的unsigned long (32bit 无符号整数)

    [0,1,-1].pack("N*") => "\000\000\000\000\000\000\000\001\377\377\377\377"
    "\000\000\000\000\000\000\000\001\377\377\377\377".unpack("N*") => [0, 1, 4294967295]
    
  • v

    "VAX"字节顺序(小Endian)的unsigned short (16bit 无符号整数)

    [0,1,-1,32767,-32768,65535].pack("v*")
    => "\000\000\001\000\377\377\377\177\000\200\377\377"
    "\000\000\001\000\377\377\377\177\000\200\377\377".unpack("v*")
    => [0, 1, 65535, 32767, 32768, 65535]
    
  • V

    "VAX"字节顺序(小Endian)的unsigned long (32bit 无符号整数)

    [0,1,-1].pack("V*") => "\000\000\000\000\001\000\000\000\377\377\377\377"
    "\000\000\000\000\001\000\000\000\377\377\377\377".unpack("V*") => [0, 1, 4294967295]
    
  • f

    单精度浮点数(取决于系统)

    IA-32 (x86) (IEEE754 单精度 小Endian):

    [1.0].pack("f") => "\000\000\200?"
    

    sparc (IEEE754 单精度 大Endian):

    [1.0].pack("f") => "?\200\000\000"
    
  • d

    双精度浮点数(取决于系统)

    IA-32 (IEEE754 双精度 小Endian):

    [1.0].pack("d") => "\000\000\000\000\000\000\360?"
    

    sparc (IEEE754 双精度 大Endian):

    [1.0].pack("d") => "?\360\000\000\000\000\000\000"
    
  • e

    小Endian的单精度浮点数(取决于系统)

    IA-32:

    [1.0].pack("e") => "\000\000\200?"
    

    sparc:

    [1.0].pack("e") => "\000\000\200?"
    
  • E

    小Endian的双精度浮点数(取决于系统)

    IA-32:

    [1.0].pack("E") => "\000\000\000\000\000\000\360?"
    

    sparc:

    [1.0].pack("E") => "\000\000\000\000\000\000\360?"
    
  • g

    大Endian的单精度浮点数(取决于系统)

    IA-32:

    [1.0].pack("g") => "?\200\000\000"
    

    sparc:

    [1.0].pack("g") => "?\200\000\000"
    
  • G

    大Endian的双精度浮点数(取决于系统)

    IA-32:

    [1.0].pack("G") => "?\360\000\000\000\000\000\000"
    

    sparc:

    [1.0].pack("G") => "?\360\000\000\000\000\000\000"
    
  • p

    指向null终点字符串的指针

    [""].pack("p") => "\310\037\034\010"
    ["a", "b", "c"].pack("p3") => " =\030\010\340^\030\010\360^\030\010"
    [nil].pack("p") => "\000\000\000\000"
    
  • P

    指向结构体(定长字符串)的指针

    [nil].pack("P") => "\000\000\000\000"
    ["abc"].pack("P3") => "x*\024\010"
    ["abc"].pack("P4") => ArgumentError: too short buffer for P(3 for 4)
    [""].pack("P") => ArgumentError: too short buffer for P(0 for 1)
    
  • u

    被uuencode编码的字符串

    [""].pack("u") => ""
    ["a"].pack("u") => "!80``\n"
    ["abc"].pack("u") => "#86)C\n"
    ["abcd"].pack("u") => "$86)C9```\n"
    ["a"*45].pack("u") => "M86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A\n"
    ["a"*46].pack("u") => "M86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A\n!80``\n"
    ["abcdefghi"].pack("u6") => "&86)C9&5F\n#9VAI\n"
    
  • U

    utf-8

    [0].pack("U") => "\000"
    [1].pack("U") => "\001"
    [0x7f].pack("U") => "\177"
    [0x80].pack("U") => "\302\200"
    [0x7fffffff].pack("U") => "\375\277\277\277\277\277"
    [0x80000000].pack("U") => ArgumentError
    [0,256,65536].pack("U3") => "\000\304\200\360\220\200\200"
    "\000\304\200\360\220\200\200".unpack("U3") => [0, 256, 65536]
    "\000\304\200\360\220\200\200".unpack("U") => [0]
    "\000\304\200\360\220\200\200".unpack("U*") => [0, 256, 65536]
    
  • w

    BER压缩整数

    用7位来表现1字节, 这样就能以最少的字节数来表现任意大小的0以上的整数。各字节的最高位中除了数据的末尾以外,肯定还有个1(也就是说, 最高位可以表示数据伸展到的位置)。

    BER是Basic Encoding Rules的缩略语(BER并非只能处理整数。ASN.1的编码中也用到了它)

  • x

    读入null字节/1字节

  • X

    后退1字节

  • @

    向绝对位置移动

用例

下面是一些pack/unpack的用例。

其实有的问题并不需要使用pack, 但我们还是给了出它的例子。主要是因为pack很容易进行加密, 我们想向不愿使用pack的人提供一点新思路。

  • 将数值(字符代码)的数组变为字符串的例子

    p [82, 117, 98, 121].pack("cccc")
    => "Ruby"
    p [82, 117, 98, 121].pack("c4")
    => "Ruby"
    p [82, 117, 98, 121].pack("c*")
    => "Ruby"
    s = ""
    [82, 117, 98, 121].each {|c| s << c}
    p s
    => "Ruby"
    p [82, 117, 98, 121].collect {|c| sprintf "%c", c}.join
    => "Ruby"
    p [82, 117, 98, 121].inject("") {|s, c| s << c}
    => "Ruby"
    
  • 将字符串变为数值(字符代码)的数组的例子

    p "Ruby".unpack('C*')
    => [82, 117, 98, 121]
    a = []
    "Ruby".each_byte {|c| a << c}
    p a
    => [82, 117, 98, 121]
    
  • 可以用"x"来处理null字节

    p [82, 117, 98, 121].pack("ccxxcc")
    => "Ru\000\000by"
    
  • 可以用"x"来读取字符

    p "Ru\0\0by".unpack('ccxxcc')
    => [82, 117, 98, 121]
    
  • 将Hex dump变为数值数组的例子

    p "61 62 63 64 65 66".delete(' ').to_a.pack('H*').unpack('C*')
    => [97, 98, 99, 100, 101, 102]
    p "61 62 63 64 65 66".split.collect {|c| c.hex}
    => [97, 98, 99, 100, 101, 102]
    
  • 在二进制和16进制数的pack中, 指定的长度并不是指生成的字节数, 而是指位或半字节的个数

    p [0b01010010, 0b01110101, 0b01100010, 0b01111001].pack("C4")
    => "Ruby"
    p ["01010010011101010110001001111001"].pack("B32") # 8 bits * 4
    => "Ruby"
    p [0x52, 0x75, 0x62, 0x79].pack("C4")
    => "Ruby"
    p ["52756279"].pack("H8")  # 2 nybbles * 4
    => "Ruby"
    
  • 模板字符'a'的长度指定 只适用于一个字符串

    p  ["RUBY", "u", "b", "y"].pack("a4")
    => "RUBY"
    p ["RUBY", "u", "b", "y"].pack("aaaa")
    => "Ruby"
    p ["RUBY", "u", "b", "y"].pack("a*aaa")
    => "RUBYuby"
    
  • 在模板字符"a"中, 若长度不够时, 就用null字符进行填充

    p ["Ruby"].pack("a8")
    => "Ruby\000\000\000\000"
    
  • 小Endian和大Endian

    p [1,2].pack("s2")
    => "\000\001\000\002" # 在大Endian的系统中的输出
    => "\001\000\002\000" # 在小Endian的系统中的输出
    p [1,2].pack("n2")
    => "\000\001\000\002" # 系统无关的大Endian
    p [1,2].pack("v2")
    => "\001\000\002\000" # 系统无关的小Endian
    
  • 网络字节顺序的 signed long

    s = "\xff\xff\xff\xfe"
    n = s.unpack("N")[0]
    if n[31] == 1
      n = -((n ^ 0xffff_ffff) + 1)
    end
    p n
    => -2
    
  • 网络字节顺序的 signed long(第2个)

    s = "\xff\xff\xff\xfe"
    p n = s.unpack("N").pack("l").unpack("l")[0]
    => -2
    
  • IP地址

    require 'socket'
    p Socket.gethostbyname("localhost")[3].unpack("C4").join(".")
    => "127.0.0.1"
    p "127.0.0.1".split(".").collect {|c| c.to_i}.pack("C4")
    => "\177\000\000\001"
    
  • sockaddr_in 结构体

    require 'socket'
    p [Socket::AF_INET,
       Socket.getservbyname('echo'),
       127, 0, 0, 1].pack("s n C4 x8")
    => "\002\000\000\a\177\000\000\001\000\000\000\000\000\000\000\000"
    

    ruby 1.7 特性: 除了pack/unpack以外, 您还可以使用Socket.pack_sockaddr_in 和 Socket.unpack_sockaddr_in方法。

  • '\0'终点字符串的地址

    模板字符 "p" 和 "P"是为了处理C语言层的接口而存在的(例如ioctl)。

    p ["foo"].pack("p")
    => "8\266\021\010"
    

    结果字符串看起来乱七八糟, 实际上它表示的是字符串"foo\0"的地址(二进制形式)。您可以像下面这样,把它变成您熟悉的形式

    printf "%#010x\n", "8\266\021\010".unpack("L")[0]
    => 0x0811b638
    

    在pack的结果被GC回收之前, 地址所指的对象(在本例中是"foo\0")保证不会被GC所回收.

    您只能使用pack的结果来unpack("p")和unpack("P")。

    p ["foo"].pack("p").unpack("p")
    => ["foo"]
    p "8\266\021\010".unpack("p")
    => -:1:in `unpack': no associated pointer (ArgumentError)
            from -:1
    

    ruby 1.7 特性: "p"和"P"被解释为NULL指针, 它负责对nil进行特殊的处理。(下面是在普通的32bit机器上的结果)

    p [nil].pack("p")        #=> "\000\000\000\000"
    p "\0\0\0\0".unpack("p") #=> [nil]
    
  • 结构体的地址

    例如, 表示

    struct {
      int   a;
      short b;
      long  c;
    } v = {1,2,3};
    

    的字符串是

    v = [1,2,3].pack("i!s!l!")
    

    (考虑到byte alignment的问题, 可能需要进行适当的padding才行)

    您可以使用

    p [v].pack("P")
    => "\300\265\021\010"
    

    来获得指向该结构体的地址。