大部分语言能够直接操作内存,比如C语言,能够通过内存的地址和大小,任意的修改值,在Perl,你不能任意的操作内存,但pack/unpack函数,其给你提供了一个好的选择.
pack TEMPLATE,LIST
把LIST里面的值看成是TEMPLATE指定的格式,然后转换为字节序(即内存保存的形式).
unpack TEMPLATE,EXPR
把EXPR转换为TEMPLATE指定的格式.
通过pack转换后的值将模拟一块内存,保存转换后的字节序;而unoack通过TEMPLATE指定的格式分块取出字节序,转换为指定的格式.
TEMPLATE大致分为两种.整数型和字符型.在处理时有一些差别.
整数格式
Format Description
c,C A signed/unsigned char (8-bit integer)
value
s,S A signed/unsigned short, always 16 bits
l,L A signed/unsigned long, always 32 bits
q,Q A signed/unsigned quad (64-bit integer)
value
i,I A signed/unsigned integer, native
format
n,N A 16/32 bit value in
"network" (big-endian) order
v,V A 16/32 bit value in "VAX"
(little-endian) order
U A Unicode character number. Encodes to a
character in character mode and UTF-8 (or UTF-EBCDIC in EBCDIC platforms) in
byte mode.
因为整数型规定了字节长度,所以后面接的数字表示需要格式化列表中的几个元素.*表示全部.
$foo = pack("s2",1,2);
"\1\0\2\0" on little-endian
"\0\1\0\2" on big-endian
字符格式
Format Description
a,A A null/space padded string
b,B A bit (binary) string in
ascending/descending bit order
h,H A hexadecimal string, low/high nybble
first
Z A null terminated string
因为字符型没有规定字符长度,所以后面接的数字表示每个元素接收的字符数,只是对一个元素而言.
ord(pack('b8','00100110')) produces 100 (4
+ 32 + 64)
ord(pack('B8','00100110')) produces 38 (32
+ 4 + 2)
pack('h4','1234') produces 0x21,0x43
pack('H4','1234') produces 0x12,0x34
pack('a8',"hello") produces
"hello\0\0\0"
pack('Z8',"hello") produces
"hello\0\0\0"
pack('A8',"hello") produces "hello"
unpack('a8',"hello\0\0\0")
produces "hello\0\0\0"
unpack('Z8',"hello\0\0\0")
produces "hello"
unpack('A8',"hello") produces "hello"
unpack('A8',"hello\0\0\0")
produces "hello"
特殊格式
x A
null byte.
X Back
up a byte.
@ Null fill or truncate to absolute position,
counted from the start of the innermost ()-group.
. Null
fill or truncate to absolute position specified by value.
( Start of a ()-group.
/
Unicode
pack和unpack有2种模式:字符模式(C0)
,UTF8模式(U0)
默认为C0模式,如果格式开始为U,则为U0模式.
我的理解.转换出的格式,U0的utf8 flag为on,而C0的utf-8 flag为off.
printencode( "cp936", pack( "U", 0x53cd ) )
printencode( "cp936", decode("utf-8", pack( "C0U",
0x53cd ) ) )
上面的例子都打印汉字”反”.
U默认为U0模式,直接转换为String,而C0模式转换为了Octets,所以需要decode函数转换为String.
附:
字符串与数字的转换
十进制的数字可以在数字和字符串之间自动转换.带0前缀的十六进制和八进制字符串不能自动转换为相应的数字.必须通过函数来转换.数字转换为字符串将先把数字转换为十进制,然后把十进制数字转换为字符.
hex把字符串看成十六进制并返回相应的十进制数字
可省略0x前缀,参数为字符串
oct把字符串看成相应前缀的进制转换为十进制数字.
默认为八进制,可省略0前缀,可选 0x,0b参数为字符串
chr返回数字所代表的字符.
参数为数字
ord返回字符串第一个字符的数字形式
参数为字符串
hex “0x10”hex 0x10区别
因为hex把参数看成字符串, 0x10为16,然后把16看成十六进制字符串转换为十进制数字22.
chr(“0x48”)和chr(0x48)区别
因为chr把参数看成数字,所以”0x48”转换为数字为0,所以chr(“0x48”) ==chr(0);
对于后面接字符串参数的函数(hex,oct,ord),如果参数为数字,先转换为十进制数字,然后在把数字转换为字符串,最后才传递给函数来处理.
对于后面接数字参数的函数(chr),如果参数为字符串,就要转换为十进制数字,然后在传递给函数处理.
比较零乱,慢慢整理修改了
参考 perlpacktut,perldoc pack hex oct chr ord