打包数据
快速参考
这些表格总结了打包和解包的指令。
整数
Directive | Meaning
--------------|---------------------------------------------------------------
C | 8-bit unsigned (unsigned char)
S | 16-bit unsigned, native endian (uint16_t)
L | 32-bit unsigned, native endian (uint32_t)
Q | 64-bit unsigned, native endian (uint64_t)
J | pointer width unsigned, native endian (uintptr_t)
c | 8-bit signed (signed char)
s | 16-bit signed, native endian (int16_t)
l | 32-bit signed, native endian (int32_t)
q | 64-bit signed, native endian (int64_t)
j | pointer width signed, native endian (intptr_t)
S_ S! | unsigned short, native endian
I I_ I! | unsigned int, native endian
L_ L! | unsigned long, native endian
Q_ Q! | unsigned long long, native endian
| (raises ArgumentError if the platform has no long long type)
J! | uintptr_t, native endian (same with J)
s_ s! | signed short, native endian
i i_ i! | signed int, native endian
l_ l! | signed long, native endian
q_ q! | signed long long, native endian
| (raises ArgumentError if the platform has no long long type)
j! | intptr_t, native endian (same with j)
S> s> S!> s!> | each the same as the directive without >, but big endian
L> l> L!> l!> | S> is the same as n
I!> i!> | L> is the same as N
Q> q> Q!> q!> |
J> j> J!> j!> |
S< s< S!< s!< | each the same as the directive without <, but little endian
L< l< L!< l!< | S< is the same as v
I!< i!< | L< is the same as V
Q< q< Q!< q!< |
J< j< J!< j!< |
n | 16-bit unsigned, network (big-endian) byte order
N | 32-bit unsigned, network (big-endian) byte order
v | 16-bit unsigned, VAX (little-endian) byte order
V | 32-bit unsigned, VAX (little-endian) byte order
U | UTF-8 character
w | BER-compressed integer
浮点数
Directive | Meaning ----------|-------------------------------------------------- D d | double-precision, native format F f | single-precision, native format E | double-precision, little-endian byte order e | single-precision, little-endian byte order G | double-precision, network (big-endian) byte order g | single-precision, network (big-endian) byte order
字符串
Directive | Meaning
----------|-----------------------------------------------------------------
A | arbitrary binary string (remove trailing nulls and ASCII spaces)
a | arbitrary binary string
Z | null-terminated string
B | bit string (MSB first)
b | bit string (LSB first)
H | hex string (high nibble first)
h | hex string (low nibble first)
u | UU-encoded string
M | quoted-printable, MIME encoding (see RFC2045)
m | base64 encoded string (RFC 2045) (default)
| (base64 encoded string (RFC 4648) if followed by 0)
P | pointer to a structure (fixed-length string)
p | pointer to a null-terminated string
打包的附加指令
Directive | Meaning ----------|---------------------------------------------------------------- @ | moves to absolute position X | back up a byte x | null byte
解包的附加指令
Directive | Meaning ----------|---------------------------------------------------------------- @ | skip to the offset given by the length argument X | skip backward one byte x | skip forward one byte
打包和解包
某些 Ruby 核心方法用于处理数据的打包和解包。
-
方法
Array#pack: 将数组self的每个元素格式化为二进制字符串;返回该字符串。 -
方法
String#unpack: 从字符串self中提取数据,形成成为新数组元素的对象;返回该数组。 -
方法
String#unpack1: 执行相同操作,但只解包并返回第一个提取的对象。
这些方法中的每一种都接受一个字符串 template,该字符串由零个或多个指令字符组成,每个指令字符后跟零个或多个修饰符字符。
示例(指令 'C' 指定“无符号字符”)
[65].pack('C') # => "A" # One element, one directive. [65, 66].pack('CC') # => "AB" # Two elements, two directives. [65, 66].pack('C') # => "A" # Extra element is ignored. [65].pack('') # => "" # No directives. [65].pack('CC') # Extra directive raises ArgumentError. 'A'.unpack('C') # => [65] # One character, one directive. 'AB'.unpack('CC') # => [65, 66] # Two characters, two directives. 'AB'.unpack('C') # => [65] # Extra character is ignored. 'A'.unpack('CC') # => [65, nil] # Extra directive generates nil. 'AB'.unpack('') # => [] # No directives.
字符串 template 可以包含任何有效的指令组合(指令 'c' 指定“有符号字符”)
[65, -1].pack('cC') # => "A\xFF" "A\xFF".unpack('cC') # => [65, 255]
字符串 template 可以包含空格(会被忽略)和注释,注释以字符 '#' 开始,一直到下一个换行符(包含换行符)为止。
[0,1].pack(" C #foo \n C ") # => "\x00\x01" "\0\1".unpack(" C #foo \n C ") # => [0, 1]
任何指令都可以后跟以下任一修饰符:
-
'*'- 该指令将被应用尽可能多的次数。[65, 66].pack('C*') # => "AB" 'AB'.unpack('C*') # => [65, 66]
-
整数
count- 该指令将被应用count次。[65, 66].pack('C2') # => "AB" [65, 66].pack('C3') # Raises ArgumentError. 'AB'.unpack('C2') # => [65, 66] 'AB'.unpack('C3') # => [65, 66, nil]
注意:指令
%w[A a Z m]使用count的方式不同;请参阅 字符串指令。
如果元素不适合提供的指令,则只编码最低有效位。
[257].pack("C").unpack("C") # => [1]
打包方法
方法 Array#pack 接受可选的关键字参数 buffer,该参数指定目标字符串(而不是新字符串)。
[65, 66].pack('C*', buffer: 'foo') # => "fooAB"
该方法可以接受一个块。
# Packed string is passed to the block. [65, 66].pack('C*') {|s| p s } # => "AB"
解包方法
方法 String#unpack 和 String#unpack1 都接受一个可选的关键字参数 offset,该参数指定字符串中的偏移量。
'ABC'.unpack('C*', offset: 1) # => [66, 67] 'ABC'.unpack1('C*', offset: 1) # => 66
这两种方法都可以接受一个块。
# Each unpacked object is passed to the block. ret = [] "ABCD".unpack("C*") {|c| ret << c } ret # => [65, 66, 67, 68] # The single unpacked object is passed to the block. 'AB'.unpack1('C*') {|ele| p ele } # => 65
整数指令
每个整数指令指定输入或输出数组中一个元素的打包或解包。
8位整数指令
-
'c'- 8位有符号整数(类似于 C 的signed char)。[0, 1, 255].pack('c*') # => "\x00\x01\xFF" s = [0, 1, -1].pack('c*') # => "\x00\x01\xFF" s.unpack('c*') # => [0, 1, -1]
-
'C'- 8位无符号整数(类似于 C 的unsigned char)。[0, 1, 255].pack('C*') # => "\x00\x01\xFF" s = [0, 1, -1].pack('C*') # => "\x00\x01\xFF" s.unpack('C*') # => [0, 1, 255]
16位整数指令
-
's'- 16位有符号整数,原生字节序(类似于 C 的int16_t)。[513, -514].pack('s*') # => "\x01\x02\xFE\xFD" s = [513, 65022].pack('s*') # => "\x01\x02\xFE\xFD" s.unpack('s*') # => [513, -514]
-
'S'- 16位无符号整数,原生字节序(类似于 C 的uint16_t)。[513, -514].pack('S*') # => "\x01\x02\xFE\xFD" s = [513, 65022].pack('S*') # => "\x01\x02\xFE\xFD" s.unpack('S*') # => [513, 65022]
-
'n'- 16位网络字节序整数,大端。s = [0, 1, -1, 32767, -32768, 65535].pack('n*') # => "\x00\x00\x00\x01\xFF\xFF\x7F\xFF\x80\x00\xFF\xFF" s.unpack('n*') # => [0, 1, 65535, 32767, 32768, 65535]
-
'v'- 16位 VAX 整数,小端。s = [0, 1, -1, 32767, -32768, 65535].pack('v*') # => "\x00\x00\x01\x00\xFF\xFF\xFF\x7F\x00\x80\xFF\xFF" s.unpack('v*') # => [0, 1, 65535, 32767, 32768, 65535]
32位整数指令
-
'l'- 32位有符号整数,原生字节序(类似于 C 的int32_t)。s = [67305985, -50462977].pack('l*') # => "\x01\x02\x03\x04\xFF\xFE\xFD\xFC" s.unpack('l*') # => [67305985, -50462977]
-
'L'- 32位无符号整数,原生字节序(类似于 C 的uint32_t)。s = [67305985, 4244504319].pack('L*') # => "\x01\x02\x03\x04\xFF\xFE\xFD\xFC" s.unpack('L*') # => [67305985, 4244504319]
-
'N'- 32位网络字节序整数,大端。s = [0,1,-1].pack('N*') # => "\x00\x00\x00\x00\x00\x00\x00\x01\xFF\xFF\xFF\xFF" s.unpack('N*') # => [0, 1, 4294967295]
-
'V'- 32位 VAX 整数,小端。s = [0,1,-1].pack('V*') # => "\x00\x00\x00\x00\x01\x00\x00\x00\xFF\xFF\xFF\xFF" s.unpack('v*') # => [0, 0, 1, 0, 65535, 65535]
64位整数指令
-
'q'- 64位有符号整数,原生字节序(类似于 C 的int64_t)。s = [578437695752307201, -506097522914230529].pack('q*') # => "\x01\x02\x03\x04\x05\x06\a\b\xFF\xFE\xFD\xFC\xFB\xFA\xF9\xF8" s.unpack('q*') # => [578437695752307201, -506097522914230529]
-
'Q'- 64位无符号整数,原生字节序(类似于 C 的uint64_t)。s = [578437695752307201, 17940646550795321087].pack('Q*') # => "\x01\x02\x03\x04\x05\x06\a\b\xFF\xFE\xFD\xFC\xFB\xFA\xF9\xF8" s.unpack('Q*') # => [578437695752307201, 17940646550795321087]
平台相关的整数指令
-
'i'- 平台相关位宽的有符号整数,原生字节序(类似于 C 的int)。s = [67305985, -50462977].pack('i*') # => "\x01\x02\x03\x04\xFF\xFE\xFD\xFC" s.unpack('i*') # => [67305985, -50462977]
-
'I'- 平台相关位宽的无符号整数,原生字节序(类似于 C 的unsigned int)。s = [67305985, -50462977].pack('I*') # => "\x01\x02\x03\x04\xFF\xFE\xFD\xFC" s.unpack('I*') # => [67305985, 4244504319]
-
'j'- 指针宽度有符号整数,原生字节序(类似于 C 的intptr_t)。s = [67305985, -50462977].pack('j*') # => "\x01\x02\x03\x04\x00\x00\x00\x00\xFF\xFE\xFD\xFC\xFF\xFF\xFF\xFF" s.unpack('j*') # => [67305985, -50462977]
-
'J'- 指针宽度无符号整数,原生字节序(类似于 C 的uintptr_t)。s = [67305985, 4244504319].pack('J*') # => "\x01\x02\x03\x04\x00\x00\x00\x00\xFF\xFE\xFD\xFC\x00\x00\x00\x00" s.unpack('J*') # => [67305985, 4244504319]
其他整数指令
-
'U'- UTF-8 字符。s = [4194304].pack('U*') # => "\xF8\x90\x80\x80\x80" s.unpack('U*') # => [4194304]
-
'r'- 有符号 LEB128 编码整数(参见 Signed LEB128)。s = [1, 127, -128, 16383, -16384].pack("r*") # => "\x01\xFF\x00\x80\x7F\xFF\xFF\x00\x80\x80\x7F" s.unpack('r*') # => [1, 127, -128, 16383, -16384]
-
'R'- 无符号 LEB128 编码整数(参见 Unsigned LEB128)。s = [1, 127, 128, 16383, 16384].pack("R*") # => "\x01\x7F\x80\x01\xFF\x7F\x80\x80\x01" s.unpack('R*') # => [1, 127, 128, 16383, 16384]
-
'w'- BER 编码整数(参见 BER encoding)。s = [1073741823].pack('w*') # => "\x83\xFF\xFF\xFF\x7F" s.unpack('w*') # => [1073741823]
整数指令的修饰符
对于以下指令,可以添加 '!' 或 '_' 修饰符作为底层平台的原生大小。
-
'i','I'- Cint,始终为原生大小。 -
's','S'- Cshort。 -
'l','L'- Clong。 -
'q','Q'- Clong long,如果可用。 -
'j','J'- Cintptr_t,始终为原生大小。
原生大小修饰符对于始终原生大小的指令会被静默忽略。
字节序修饰符也可以附加到上述指令中。
-
'>'- 大端。 -
'<'- 小端。
浮点数指令
每个浮点数指令指定输入或输出数组中一个元素的打包或解包。
单精度浮点数指令
-
'F'或'f'- 原生格式。s = [3.0].pack('F') # => "\x00\x00@@" s.unpack('F') # => [3.0]
-
'e'- 小端。s = [3.0].pack('e') # => "\x00\x00@@" s.unpack('e') # => [3.0]
-
'g'- 大端。s = [3.0].pack('g') # => "@@\x00\x00" s.unpack('g') # => [3.0]
双精度浮点数指令
-
'D'或'd'- 原生格式。s = [3.0].pack('D') # => "\x00\x00\x00\x00\x00\x00\b@" s.unpack('D') # => [3.0]
-
'E'- 小端。s = [3.0].pack('E') # => "\x00\x00\x00\x00\x00\x00\b@" s.unpack('E') # => [3.0]
-
'G'- 大端。s = [3.0].pack('G') # => "@\b\x00\x00\x00\x00\x00\x00" s.unpack('G') # => [3.0]
浮点数指令可以是无穷大或非数字。
inf = 1.0/0.0 # => Infinity [inf].pack('f') # => "\x00\x00\x80\x7F" "\x00\x00\x80\x7F".unpack('f') # => [Infinity] nan = inf/inf # => NaN [nan].pack('f') # => "\x00\x00\xC0\x7F" "\x00\x00\xC0\x7F".unpack('f') # => [NaN]
字符串指令
每个字符串指令指定输入或输出字符串中一个字节的打包或解包。
二进制字符串指令
-
'A'- 任意二进制字符串(用空格填充;count是宽度);nil被视为空字符串。['foo'].pack('A') # => "f" ['foo'].pack('A*') # => "foo" ['foo'].pack('A2') # => "fo" ['foo'].pack('A4') # => "foo " [nil].pack('A') # => " " [nil].pack('A*') # => "" [nil].pack('A2') # => " " [nil].pack('A4') # => " " "foo\0".unpack('A') # => ["f"] "foo\0".unpack('A4') # => ["foo"] "foo\0bar".unpack('A10') # => ["foo\x00bar"] # Reads past "\0". "foo ".unpack('A') # => ["f"] "foo ".unpack('A4') # => ["foo"] "foo".unpack('A4') # => ["foo"] russian = "\u{442 435 441 442}" # => "тест" russian.size # => 4 russian.bytesize # => 8 [russian].pack('A') # => "\xD1" [russian].pack('A*') # => "\xD1\x82\xD0\xB5\xD1\x81\xD1\x82" russian.unpack('A') # => ["\xD1"] russian.unpack('A2') # => ["\xD1\x82"] russian.unpack('A4') # => ["\xD1\x82\xD0\xB5"] russian.unpack('A*') # => ["\xD1\x82\xD0\xB5\xD1\x81\xD1\x82"]
-
'a'- 任意二进制字符串(用空字符填充;count是宽度)。["foo"].pack('a') # => "f" ["foo"].pack('a*') # => "foo" ["foo"].pack('a2') # => "fo" ["foo\0"].pack('a4') # => "foo\x00" [nil].pack('a') # => "\x00" [nil].pack('a*') # => "" [nil].pack('a2') # => "\x00\x00" [nil].pack('a4') # => "\x00\x00\x00\x00" "foo\0".unpack('a') # => ["f"] "foo\0".unpack('a4') # => ["foo\x00"] "foo ".unpack('a4') # => ["foo "] "foo".unpack('a4') # => ["foo"] "foo\0bar".unpack('a4') # => ["foo\x00"] # Reads past "\0".
-
'Z'- 与'a'相同,但当使用'*'时,空字符会被添加或忽略。["foo"].pack('Z*') # => "foo\x00" [nil].pack('Z*') # => "\x00" "foo\0".unpack('Z*') # => ["foo"] "foo".unpack('Z*') # => ["foo"] "foo\0bar".unpack('Z*') # => ["foo"] # Does not read past "\0".
比特字符串指令
-
'B'- 比特字符串(高位字节在前)。['11111111' + '00000000'].pack('B*') # => "\xFF\x00" ['10000000' + '01000000'].pack('B*') # => "\x80@" ['1'].pack('B0') # => "" ['1'].pack('B1') # => "\x80" ['1'].pack('B2') # => "\x80\x00" ['1'].pack('B3') # => "\x80\x00" ['1'].pack('B4') # => "\x80\x00\x00" ['1'].pack('B5') # => "\x80\x00\x00" ['1'].pack('B6') # => "\x80\x00\x00\x00" "\xff\x00".unpack("B*") # => ["1111111100000000"] "\x01\x02".unpack("B*") # => ["0000000100000010"] "".unpack("B0") # => [""] "\x80".unpack("B1") # => ["1"] "\x80".unpack("B2") # => ["10"] "\x80".unpack("B3") # => ["100"]
-
'b'- 比特字符串(低位字节在前)。['11111111' + '00000000'].pack('b*') # => "\xFF\x00" ['10000000' + '01000000'].pack('b*') # => "\x01\x02" ['1'].pack('b0') # => "" ['1'].pack('b1') # => "\x01" ['1'].pack('b2') # => "\x01\x00" ['1'].pack('b3') # => "\x01\x00" ['1'].pack('b4') # => "\x01\x00\x00" ['1'].pack('b5') # => "\x01\x00\x00" ['1'].pack('b6') # => "\x01\x00\x00\x00" "\xff\x00".unpack("b*") # => ["1111111100000000"] "\x01\x02".unpack("b*") # => ["1000000001000000"] "".unpack("b0") # => [""] "\x01".unpack("b1") # => ["1"] "\x01".unpack("b2") # => ["10"] "\x01".unpack("b3") # => ["100"]
十六进制字符串指令
-
'H'- 十六进制字符串(高位 nibble 在前)。['10ef'].pack('H*') # => "\x10\xEF" ['10ef'].pack('H0') # => "" ['10ef'].pack('H3') # => "\x10\xE0" ['10ef'].pack('H5') # => "\x10\xEF\x00" ['fff'].pack('H3') # => "\xFF\xF0" ['fff'].pack('H4') # => "\xFF\xF0" ['fff'].pack('H5') # => "\xFF\xF0\x00" ['fff'].pack('H6') # => "\xFF\xF0\x00" ['fff'].pack('H7') # => "\xFF\xF0\x00\x00" ['fff'].pack('H8') # => "\xFF\xF0\x00\x00" "\x10\xef".unpack('H*') # => ["10ef"] "\x10\xef".unpack('H0') # => [""] "\x10\xef".unpack('H1') # => ["1"] "\x10\xef".unpack('H2') # => ["10"] "\x10\xef".unpack('H3') # => ["10e"] "\x10\xef".unpack('H4') # => ["10ef"] "\x10\xef".unpack('H5') # => ["10ef"]
-
'h'- 十六进制字符串(低位 nibble 在前)。['10ef'].pack('h*') # => "\x01\xFE" ['10ef'].pack('h0') # => "" ['10ef'].pack('h3') # => "\x01\x0E" ['10ef'].pack('h5') # => "\x01\xFE\x00" ['fff'].pack('h3') # => "\xFF\x0F" ['fff'].pack('h4') # => "\xFF\x0F" ['fff'].pack('h5') # => "\xFF\x0F\x00" ['fff'].pack('h6') # => "\xFF\x0F\x00" ['fff'].pack('h7') # => "\xFF\x0F\x00\x00" ['fff'].pack('h8') # => "\xFF\x0F\x00\x00" "\x01\xfe".unpack('h*') # => ["10ef"] "\x01\xfe".unpack('h0') # => [""] "\x01\xfe".unpack('h1') # => ["1"] "\x01\xfe".unpack('h2') # => ["10"] "\x01\xfe".unpack('h3') # => ["10e"] "\x01\xfe".unpack('h4') # => ["10ef"] "\x01\xfe".unpack('h5') # => ["10ef"]
指针字符串指令
-
'P'- 指向结构体(固定长度字符串)。s = ['abc'].pack('P') # => "\xE0O\x7F\xE5\xA1\x01\x00\x00" s.unpack('P*') # => ["abc"] ".".unpack("P") # => [] ("\0" * 8).unpack("P") # => [nil] [nil].pack("P") # => "\x00\x00\x00\x00\x00\x00\x00\x00"
-
'p'- 指向空终止字符串。s = ['abc'].pack('p') # => "(\xE4u\xE5\xA1\x01\x00\x00" s.unpack('p*') # => ["abc"] ".".unpack("p") # => [] ("\0" * 8).unpack("p") # => [nil] [nil].pack("p") # => "\x00\x00\x00\x00\x00\x00\x00\x00"
其他字符串指令
-
'M'- Quoted-printable,MIME 编码;文本模式,但输入必须使用 LF,输出也使用 LF;(参见 RFC 2045)。["a b c\td \ne"].pack('M') # => "a b c\td =\n\ne=\n" ["\0"].pack('M') # => "=00=\n" ["a"*1023].pack('M') == ("a"*73+"=\n")*14+"a=\n" # => true ("a"*73+"=\na=\n").unpack('M') == ["a"*74] # => true (("a"*73+"=\n")*14+"a=\n").unpack('M') == ["a"*1023] # => true "a b c\td =\n\ne=\n".unpack('M') # => ["a b c\td \ne"] "=00=\n".unpack('M') # => ["\x00"] "pre=31=32=33after".unpack('M') # => ["pre123after"] "pre=\nafter".unpack('M') # => ["preafter"] "pre=\r\nafter".unpack('M') # => ["preafter"] "pre=".unpack('M') # => ["pre="] "pre=\r".unpack('M') # => ["pre=\r"] "pre=hoge".unpack('M') # => ["pre=hoge"] "pre==31after".unpack('M') # => ["pre==31after"] "pre===31after".unpack('M') # => ["pre===31after"]
-
'm'- Base64 编码字符串;count指定每行之间的输入字节数,向下取整到 3 的最近倍数;如果count为零,则不添加换行符;(参见 RFC 4648)。[""].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" "".unpack('m') # => [""] "AA==\n".unpack('m') # => ["\x00"] "AAA=\n".unpack('m') # => ["\x00\x00"] "AAAA\n".unpack('m') # => ["\x00\x00\x00"] "/w==\n".unpack('m') # => ["\xFF"] "//8=\n".unpack('m') # => ["\xFF\xFF"] "////\n".unpack('m') # => ["\xFF\xFF\xFF"] "A\n".unpack('m') # => [""] "AA\n".unpack('m') # => ["\x00"] "AA=\n".unpack('m') # => ["\x00"] "AAA\n".unpack('m') # => ["\x00\x00"] [""].pack('m0') # => "" ["\0"].pack('m0') # => "AA==" ["\0\0"].pack('m0') # => "AAA=" ["\0\0\0"].pack('m0') # => "AAAA" ["\377"].pack('m0') # => "/w==" ["\377\377"].pack('m0') # => "//8=" ["\377\377\377"].pack('m0') # => "////" "".unpack('m0') # => [""] "AA==".unpack('m0') # => ["\x00"] "AAA=".unpack('m0') # => ["\x00\x00"] "AAAA".unpack('m0') # => ["\x00\x00\x00"] "/w==".unpack('m0') # => ["\xFF"] "//8=".unpack('m0') # => ["\xFF\xFF"] "////".unpack('m0') # => ["\xFF\xFF\xFF"]
-
'u'- UU 编码字符串。[""].pack("u") # => "" ["a"].pack("u") # => "!80``\n" ["aaa"].pack("u") # => "#86%A\n" "".unpack("u") # => [""] "#86)C\n".unpack("u") # => ["abc"]
偏移量指令
-
'@'- 从给定的字节偏移量开始打包;打包时,如果需要,使用空字符填充或缩小。[1, 2].pack("C@0C") # => "\x02" [1, 2].pack("C@1C") # => "\x01\x02" [1, 2].pack("C@5C") # => "\x01\x00\x00\x00\x00\x02" [*1..5].pack("CCCC@2C") # => "\x01\x02\x05"
解包时,不能移出字符串范围。
"\x01\x00\x00\x02".unpack("C@3C") # => [1, 2] "\x00".unpack("@1C") # => [nil] "\x00".unpack("@2C") # Raises ArgumentError.
-
'X'- 打包时,按给定的字节偏移量缩小。[0, 1, 2].pack("CCXC") # => "\x00\x02" [0, 1, 2].pack("CCX2C") # => "\x02"
解包时;按给定的字节偏移量倒回解包位置。
"\x00\x02".unpack("CCXC") # => [0, 2, 2]
不能移出字符串范围。
[0, 1, 2].pack("CCX3C") # Raises ArgumentError. "\x00\x02".unpack("CX3C") # Raises ArgumentError.
-
'x'- 从给定的字节偏移量之后开始打包;打包时,如果需要,使用空字符填充。[].pack("x0") # => "" [].pack("x") # => "\x00" [].pack("x8") # => "\x00\x00\x00\x00\x00\x00\x00\x00"
解包时,不能移出字符串范围。
"\x00\x00\x02".unpack("CxC") # => [0, 2] "\x00\x00\x02".unpack("x3C") # => [nil] "\x00\x00\x02".unpack("x4C") # Raises ArgumentError