ruby Array#pack String#unpack 实例

Posted by wxianfeng Sat, 26 May 2012 21:25:00 GMT

最近项目中常用到 Array#pack, String#unpack 方法,在此总结下:

Array#pack, String#unpack 可以实现不同编码之间的处理, 可以处理字节级, bit 级的一些二进制格式.

字节编码, ruby里主要是 “\nnn” 和 “\xnn” 的形式, nnn 是八进制数字, nn 是十六进制, 可以从 <<ruby编程语言>> 这本书看到相关信息.

截了张书中的图:

例子:
ASCII 码值: 0123456789
字节编码:
“\000\001\002\003\004\005\006\007\010\011” (八进制)
“\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09” (十六进制)

另外 ascii 码值是 7,8,9 的在ruby中是转义序列 “\a”, “\b”, “\t”, 所以字节编码也可以写成
\x00\x01\x02\x03\x04\x05\x06\a\b\t

1.9.2p290 :198 > a = [0,1,2,3,4,5,6,7,8,9]
 => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
1.9.2p290 :199 > a.pack("c*")
 => "\x00\x01\x02\x03\x04\x05\x06\a\b\t"
1.9.2p290 :200 > "\x00\x01\x02\x03\x04\x05\x06\a\b\t" == "\000\001\002\003\004\005\006\007\010\011"
 => true
1.9.2p290 :201 > "\011" == "\x09"
 => true
1.9.2p290 :202 > "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09" == "\000\001\002\003\004\005\006\007\010\011"
 => true

下面来看一些实例,以字符模板来讲

1, M

M         | String  | quoted printable, MIME encoding (see RFC2045)

字符串和 quoted printable 编码之间转换,常用在邮件编码中

Array#pack
ruby-1.9.2-p290 :132 > ["[www.wxianfeng.com]欢迎您注册,请您激活"].pack("M")
 => "[www.wxianfeng.com]=E6=AC=A2=E8=BF=8E=E6=82=A8=E6=B3=A8=E5=86=8C,=E8=AF=B7=\n=E6=82=A8=E6=BF=80=E6=B4=BB=\n" 

可以看到 每76个字符就多了一个 =\n , 所以如果是用在邮件的 Subject 的中的话, 应该是

["str"].pack("M").gsub(/=\n/,"")

完整的邮件Subject编码应该是 像这样:

value = ["[#{site}]请激活您的帐号"].pack("M").gsub(/=\n/, "")
subject = "=?UTF-8?Q?#{value}?="
String#unpack
ruby-1.9.2-p290 :153 > "[www.wxianfeng.com]=E6=AC=A2=E8=BF=8E=E6=82=A8=E6=B3=A8=E5=86=8C,=E8=AF=B7=\n=E6=82=A8=E6=BF=80=E6=B4=BB=\n".unpack("M")
 => ["[www.wxianfeng.com]\xE6\xAC\xA2\xE8\xBF\x8E\xE6\x82\xA8\xE6\xB3\xA8\xE5\x86\x8C,\xE8\xAF\xB7\xE6\x82\xA8\xE6\xBF\x80\xE6\xB4\xBB"] 

2, m

m         | String  | base64 encoded string (see RFC 2045, count is width)
             |         | (if count is 0, no line feed are added, see RFC 4648)

字符串和 Base64 编码之间转换

Array#pack
ruby-1.9.2-p290 :133 > ["[www.wxianfeng.com]欢迎您注册,请您激活"].pack("m")
 => "W3d3dy53eGlhbmZlbmcuY29tXeasoui/juaCqOazqOWGjCzor7fmgqjmv4Dm\ntLs=\n"

base64编码也可以用在邮件编码中,例如用在Subject中就是这样:

value = ["[#{site}]请激活您的帐号"].pack("M").gsub(/=\n/, "")
subject = "=?UTF-8?B?#{value}?="
String#unpack
ruby-1.9.2-p290 :155 > "W3d3dy53eGlhbmZlbmcuY29tXeasoui/juaCqOazqOWGjCzor7fmgqjmv4Dm\ntLs=\n".unpack("m")
 => ["[www.wxianfeng.com]\xE6\xAC\xA2\xE8\xBF\x8E\xE6\x82\xA8\xE6\xB3\xA8\xE5\x86\x8C,\xE8\xAF\xB7\xE6\x82\xA8\xE6\xBF\x80\xE6\xB4\xBB"]

3, L

 L         | Integer | 32-bit unsigned, native endian (uint32_t)

整型(ASCII)和二进制字符串相互转化,int是32为无符号的,占4个字节

Array#pack
ruby-1.9.2-p290 :139 > [65].pack("L")
 => "A\x00\x00\x00"

String#unpack
ruby-1.9.2-p290 :140 > "A\x00\x00\x00".unpack("L")
 => [65] 

4, c

c         | Integer | 8-bit signed (signed char)

整型(ASCII)和二进制字符串相互转化,int 是8位有符号的,占一个字节

Array#pack
ruby-1.9.2-p290 :142 > [77].pack("c")
 => "M" 

String#unpack
ruby-1.9.2-p290 :143 > "M".unpack("c")
 => [77] 

5, Q

Q         | Integer | 64-bit unsigned, native endian (uint64_t)

整型和二进制字符串相互转化,int是64位无符号的,占8字节

Array#pack
ruby-1.9.2-p290 :149 > [1338053358065].pack("Q")
 => "\xF1\xF11\x8A7\x01\x00\x00" 

String#unpack
ruby-1.9.2-p290 :150 > "\xF1\xF11\x8A7\x01\x00\x00".unpack("Q")
 => [1338053358065]

6, S

S         | Integer | 16-bit unsigned, native endian (uint16_t)

整型和二进制字符串转化,int是16位无符号的,占2个字节

Array#pack
ruby-1.9.2-p290 :151 > [6].pack("S")
 => "\x06\x00" 

String#unpack
ruby-1.9.2-p290 :152 > "\x06\x00".unpack("S")
 => [6] 

http://www.ruby-doc.org/core-1.9.3/Array.html#method-i-pack
http://www.ruby-doc.org/core-1.9.3/String.html#method-i-unpack
http://www.cnblogs.com/baochun968/archive/2011/10/19/2218008.html