?
本文檔使用 PHP中文網(wǎng)手冊(cè) 發(fā)布
下面就是Array#pack、String#unpack中所用到的模板字符的一覽表。模板字符后面可以跟上表示"長(zhǎng)度"的數(shù)字。若使用'*'來(lái)取代"長(zhǎng)度"的話, 則表示"剩下的所有字符"之意。
長(zhǎng)度的定義因模板字符的不同而有所差異, 大體上像
"iiii"
這樣的連續(xù)字符可以寫(xiě)成
"i4"
這個(gè)樣子。
在下面的說(shuō)明中, short和long分別表示長(zhǎng)度為2和4字節(jié)的數(shù)值(也就是通常32位機(jī)器所指的short和long的大小), 這與具體的系統(tǒng)無(wú)關(guān)。 若`s', `S', `l', `L'后面出現(xiàn)`_'或`!'(如"s!")的話, 則表示這個(gè)short或long的大小取決于具體的系統(tǒng)。
請(qǐng)注意: `i', `I' (int)的大小總是取決于系統(tǒng)的, 而`n', `N', `v', `V'的大小則是系統(tǒng)無(wú)關(guān)的(不能添加`!')。
模板字符串中的空格會(huì)被忽略。 ruby 1.7 特性: 另外,從`#'開(kāi)始到換行處或者到模板字符串結(jié)尾之間的部分會(huì)被看做是注釋。
在下面的說(shuō)明中, 若針對(duì)某問(wèn)題Array#pack和String#unpack有不同的解釋時(shí), 就使用/將兩者分開(kāi), 即采用 "Array#pack的說(shuō)明部分/String#unpack的說(shuō)明部分" 的形式加以說(shuō)明.
a
ASCII字符串(塞入null字符/保留后續(xù)的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字符串(塞入空格/刪除后續(xù)的null字符和空格)
["abc"].pack("A") => "a" ["abc"].pack("A*") => "abc" ["abc"].pack("A4") => "abc " "abc ".unpack("A4") => ["abc"] "abc\0".unpack("A4") => ["abc"]
Z
null終點(diǎn)字符串(與a
相同 / 刪除后續(xù)的null字符)
["abc"].pack("Z") => "a" ["abc"].pack("Z*") => "abc" ["abc"].pack("Z4") => "abc\0" "abc\0".unpack("Z4") => ["abc"] "abc ".unpack("Z4") => ["abc "]
b
位串(從下級(jí)位到上級(jí)位)
"\001\002".unpack("b*") => ["1000000001000000"] "\001\002".unpack("b3") => ["100"] ["1000000001000000"].pack("b*") => "\001\002"
B
位串(從上級(jí)位到下級(jí)位)
"\001\002".unpack("B*") => ["0000000100000010"] "\001\002".unpack("B9") => ["000000010"] ["0000000100000010"].pack("B*") => "\001\002"
h
16進(jìn)制字符串(下級(jí)半字節(jié)(nibble)在先)
"\x01\xfe".unpack("h*") => ["10ef"] "\x01\xfe".unpack("h3") => ["10e"] ["10ef"].pack("h*") => "\001\376"
H
16進(jìn)制字符串(上級(jí)半字節(jié)在先)
"\x01\xfe".unpack("H*") => ["01fe"] "\x01\xfe".unpack("H3") => ["01f"] ["01fe"].pack("H*") => "\001\376"
c
char (8bit 有符號(hào)整數(shù))
"\001\376".unpack("c*") => [1, -2] [1, -2].pack("c*") => "\001\376" [1, 254].pack("c*") => "\001\376"
C
unsigned char (8bit 無(wú)符號(hào)整數(shù))
"\001\376".unpack("C*") => [1, 254] [1, -2].pack("C*") => "\001\376" [1, 254].pack("C*") => "\001\376"
s
short (16bit 有符號(hào)整數(shù), 取決于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 無(wú)符號(hào)整數(shù), 取決于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 (有符號(hào)整數(shù), 取決于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 (無(wú)符號(hào)整數(shù), 取決于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 有符號(hào)整數(shù), 取決于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 無(wú)符號(hào)整數(shù), 取決于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 (有符號(hào)整數(shù), 取決于Endian和long long 的大小) (在C中無(wú)法處理long long時(shí), 就是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 (無(wú)符號(hào)整數(shù), 取決于Endian和 long long 的大小) (在C中無(wú)法處理long long時(shí), 就是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編碼過(guò)的字符串。每隔60個(gè)八位組(或在結(jié)尾)添加一個(gè)換行代碼。
Base64是一種編碼方法, 它只使用ASCII碼中的65個(gè)字符(包括[A-Za-z0-9+/]這64字符和用來(lái)padding的'='),將3個(gè)八位組(8bits * 3 = 24bits)中的二進(jìn)制代碼轉(zhuǎn)為4個(gè)(6bits * 4 = 24bits)可印刷的字符。具體細(xì)節(jié)請(qǐng)參考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") => "http://8=\n" ["\377\377\377"].pack("m") => "http:////\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
經(jīng)過(guò)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
網(wǎng)絡(luò)字節(jié)順序(大Endian)的unsigned short (16bit 無(wú)符號(hào)整數(shù))
[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
網(wǎng)絡(luò)字節(jié)順序(大Endian)的unsigned long (32bit 無(wú)符號(hào)整數(shù))
[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"字節(jié)順序(小Endian)的unsigned short (16bit 無(wú)符號(hào)整數(shù))
[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"字節(jié)順序(小Endian)的unsigned long (32bit 無(wú)符號(hào)整數(shù))
[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
單精度浮點(diǎn)數(shù)(取決于系統(tǒng))
IA-32 (x86) (IEEE754 單精度 小Endian):
[1.0].pack("f") => "\000\000\200?"
sparc (IEEE754 單精度 大Endian):
[1.0].pack("f") => "?\200\000\000"
d
雙精度浮點(diǎn)數(shù)(取決于系統(tǒng))
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的單精度浮點(diǎn)數(shù)(取決于系統(tǒng))
IA-32:
[1.0].pack("e") => "\000\000\200?"
sparc:
[1.0].pack("e") => "\000\000\200?"
E
小Endian的雙精度浮點(diǎn)數(shù)(取決于系統(tǒng))
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的單精度浮點(diǎn)數(shù)(取決于系統(tǒng))
IA-32:
[1.0].pack("g") => "?\200\000\000"
sparc:
[1.0].pack("g") => "?\200\000\000"
G
大Endian的雙精度浮點(diǎn)數(shù)(取決于系統(tǒng))
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終點(diǎn)字符串的指針
[""].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
指向結(jié)構(gòu)體(定長(zhǎng)字符串)的指針
[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壓縮整數(shù)
用7位來(lái)表現(xiàn)1字節(jié), 這樣就能以最少的字節(jié)數(shù)來(lái)表現(xiàn)任意大小的0以上的整數(shù)。各字節(jié)的最高位中除了數(shù)據(jù)的末尾以外,肯定還有個(gè)1(也就是說(shuō), 最高位可以表示數(shù)據(jù)伸展到的位置)。
BER是Basic Encoding Rules的縮略語(yǔ)(BER并非只能處理整數(shù)。ASN.1的編碼中也用到了它)
x
讀入null字節(jié)/1字節(jié)
X
后退1字節(jié)
@
向絕對(duì)位置移動(dòng)
下面是一些pack/unpack的用例。
其實(shí)有的問(wèn)題并不需要使用pack, 但我們還是給了出它的例子。主要是因?yàn)閜ack很容易進(jìn)行加密, 我們想向不愿使用pack的人提供一點(diǎn)新思路。
將數(shù)值(字符代碼)的數(shù)組變?yōu)樽址睦?/p>
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"
將字符串變?yōu)閿?shù)值(字符代碼)的數(shù)組的例子
p "Ruby".unpack('C*') => [82, 117, 98, 121] a = [] "Ruby".each_byte {|c| a << c} p a => [82, 117, 98, 121]
可以用"x"來(lái)處理null字節(jié)
p [82, 117, 98, 121].pack("ccxxcc") => "Ru\000\000by"
可以用"x"來(lái)讀取字符
p "Ru\0\0by".unpack('ccxxcc') => [82, 117, 98, 121]
將Hex dump變?yōu)閿?shù)值數(shù)組的例子
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]
在二進(jìn)制和16進(jìn)制數(shù)的pack中, 指定的長(zhǎng)度并不是指生成的字節(jié)數(shù), 而是指位或半字節(jié)的個(gè)數(shù)
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'的長(zhǎng)度指定 只適用于一個(gè)字符串
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"中, 若長(zhǎng)度不夠時(shí), 就用null字符進(jìn)行填充
p ["Ruby"].pack("a8") => "Ruby\000\000\000\000"
小Endian和大Endian
p [1,2].pack("s2") => "\000\001\000\002" # 在大Endian的系統(tǒng)中的輸出 => "\001\000\002\000" # 在小Endian的系統(tǒng)中的輸出 p [1,2].pack("n2") => "\000\001\000\002" # 系統(tǒng)無(wú)關(guān)的大Endian p [1,2].pack("v2") => "\001\000\002\000" # 系統(tǒng)無(wú)關(guān)的小Endian
網(wǎng)絡(luò)字節(jié)順序的 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
網(wǎng)絡(luò)字節(jié)順序的 signed long(第2個(gè))
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 結(jié)構(gòu)體
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'終點(diǎn)字符串的地址
模板字符 "p" 和 "P"是為了處理C語(yǔ)言層的接口而存在的(例如ioctl)。
p ["foo"].pack("p") => "8\266\021\010"
結(jié)果字符串看起來(lái)亂七八糟, 實(shí)際上它表示的是字符串"foo\0"的地址(二進(jìn)制形式)。您可以像下面這樣,把它變成您熟悉的形式
printf "%#010x\n", "8\266\021\010".unpack("L")[0] => 0x0811b638
在pack的結(jié)果被GC回收之前, 地址所指的對(duì)象(在本例中是"foo\0")保證不會(huì)被GC所回收.
您只能使用pack的結(jié)果來(lái)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指針, 它負(fù)責(zé)對(duì)nil進(jìn)行特殊的處理。(下面是在普通的32bit機(jī)器上的結(jié)果)
p [nil].pack("p") #=> "\000\000\000\000" p "\0\0\0\0".unpack("p") #=> [nil]
結(jié)構(gòu)體的地址
例如, 表示
struct { int a; short b; long c; } v = {1,2,3};
的字符串是
v = [1,2,3].pack("i!s!l!")
(考慮到byte alignment的問(wèn)題, 可能需要進(jìn)行適當(dāng)?shù)膒adding才行)
您可以使用
p [v].pack("P") => "\300\265\021\010"
來(lái)獲得指向該結(jié)構(gòu)體的地址。