direktori cari
Ruby用户指南 3、开始 4、简单的例子 5、字符串 6、正则表达式 7、数组 8、回到那些简单的例子 9、流程控制 10、迭代器 11、面向对象思维 12、方法 13、类 14、继承 15、重载方法 16、访问控制 17、单态方法 18、模块 19、过程对象 20、变量 21、全局变量 22、实变量 23、局部变量 24、类常量 25、异常处理:rescue 26、异常处理:ensure 27、存取器 28、对象的初始化 29、杂项 RGSS入门教程 1、什么是RGSS 2、开始:最简单的脚本 3、数据类型:数字 4、数据类型:常量与变量 5、数据类型:字符串 6、控制语句:条件分歧语句 7、控制语句:循环 8、函数 9、对象与类 10、显示图片 11、数组 12、哈希表(关联数组) 13、类 14、数据库 15、游戏对象 16、精灵的管理 17、窗口的管理 18、活动指令 19、场景类 Programming Ruby的翻译 Programming Ruby: The Pragmatic Programmer's Guide 前言 Roadmap Ruby.new 类,对象和变量 容器Containers,块Blocks和迭代Iterators 标准类型 深入方法 表达式Expressions 异常,捕捉和抛出(已经开始,by jellen) 模块 基本输入输出 线程和进程 当遭遇挫折 Ruby和它的世界 Ruby和Web开发 Ruby Tk Ruby 和微软的 Windows 扩展Ruby Ruby语言 (by jellen) 类和对象 (by jellen) Ruby安全 反射Reflection 内建类和方法 标准库 OO设计 网络和Web库 Windows支持 内嵌文档 交互式Ruby Shell 支持 Ruby参考手册 Ruby首页 卷首语 Ruby的启动 环境变量 对象 执行 结束时的相关处理 线程 安全模型 正则表达式 字句构造 程序 变量和常数 字面值 操作符表达式 控制结构 方法调用 类/方法的定义 内部函数 内部变量 内部常数 内部类/模块/异常类 附加库 Ruby变更记录 ruby 1.6 特性 ruby 1.7 特性 Ruby术语集 Ruby的运行平台 pack模板字符串 sprintf格式 Marshal格式 Ruby FAQ Ruby的陷阱
watak

pack模板字符串

下面就是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"
    

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


Artikel sebelumnya: Artikel seterusnya: