1.10 把Unicode字符串当成一组8位字节
时间:2007-01-04 来源:xiaoshengcaicai
1.10 把Unicode字符串当成一组8位字节
1.10.1 问题
你有一个Unicode字符串,你想让Perl把它当成一组字节看待。(比如要计算它的长度,或者为了I/0的需要)
1.10.2 解决方案
use bytes这个宏编译指令可以让perl在其词法作用域内的所有操作把字符串当成一组字节来看待。当你的代码里面调用Perl那些对字符敏感(character-aware)的函数时,可以用这个宏指令:
$ff = "\x{FB00}"; # ff ligature
$chars = length($ff); # length is one character
{
use bytes; # force byte semantics
$octets = length($ff); # length is two octets
}
$chars = length($ff); # back to character semantics
还有一种方法,Encode模块可以在Unicode字符串跟一组字节之间互相转化。如果你的代码里面没有对字符敏感的操作(译注:就是说用了use bytes也不会起到任何作用),那么就用这个方法吧:
use Encode qw(encode_utf8);
sub somefunc; # defined elsewhere
$ff = "\x{FB00}"; # ff ligature
$ff_oct = encode_utf8($ff); # convert to octets
$chars = somefunc($ff); # work with character string
$octets = somefunc($ff_oct); # work with octet string
1.10.3 讨论
跟这一章的介绍那一节说明的那样:Perl认识2种类型的字符串,一种是简单的非内插型的一组字节,另一种是一组Unicode字符,字符用的是UTF-8编码方式,每个字符可能需要超过1个字节的空间。每一个单独的字符串都有一个标志位,标记它是UTF-8编码还是一般的一组字节。Perl的I/O跟字符串操作(比如length)都会检查这个标志从而赋予字符或者字节语义。
有时候你需要以字节为单位进行操作而不是以字符为单位。举个例子,很多协议都有一个叫Content-Length的头部,这个头部指明了消息正文的字节长度。你不能简单的使用Perl的length函数来计算这个字节长度,因为如果字符串是标记了UTF-8编码的,那么length函数返回的是字符的数量而不是字符串的字节长度。
use bytes这个宏编译指令让Perl所有的函数在这个宏编译指令的词法作用域内在对字符串的处理上以字节为单位而不是字符。使用了这个宏编译指令,length函数返回的是字节的长度,read函数返回它实际读到的字节长度。由于use bytes仅在其词法作用域内起作用,所以你无法使用这个宏编译指令来改变超出它作用域的那些行为。
由于上面这个原因你需要创建这个UTF-8字符串的一个以字节为单位编码的副本(octet-encoded copy)。 这个副本跟原UTF-8字符串在在内存里面的字节流当然是一样的,区别只在于这个副本已经没有了UTF-8的标志。这样的话,那些函数只会把这个副本当成一组字节来看,跟所处的词法作用域已经没有关系了。
同样地有一个no bytes的宏编译指令用于强制以字符为单位(character semantics),还有一个decode_utf8函数,用来把以字节为单位编码的字符串转化成UTF-8编码的字符串。其实这些函数并不是很有用,因为不是所有字节字符串都是有效的UTF-8字符串,但是所有的UTF-8字符串都是有效的字节字符串。
1.10.4 参阅
bytes 这个宏编译指令的相关文档; 标准Encode模块的文档。