2009年3月19日星期四

[PerlChina] Re: 使用 Encode::Guess 遇到的��

首先,需要分清楚“字符(character)”和“字节流(Octet stream)”的概念,你的perl程序所取到的输入,以及它对外的输出(就像你用print打印)都是字节流,字节流是没有语义的,对perl来说它就是一堆字节,没有额外的意义。
而字符串和字节流是不同的,字符串有语义,它代表某个或某些个字符,直白来说,我们看到的“abcd1234“等等都是字符。而字节流可以用来表示字符串,同一个字符串,它对应的字节流可以不同,为什么呢?因为同一个字符串可以用不同的编码方式(如utf8或gb2312)来编码,编码过后得到的,便是相对应的字节流。
在perl中,你输入的一个字符串是以字节流的形式传递给perl的,如果你想perl把你输入的字符串真正当成字符串来理解和操作,你需要告诉perl这串字符的编码是什么,比如(我的环境为utf8):

use Encode;
$string="中国";
$string_decoded=decode_utf8($string);

此时,$string 对perl来说只是用utf8编码过的字节流(十六进制为\xE4\xB8\xAD\xE5\x9B\xBD),这个时候,perl只会按字节来对他操作,因为perl不知道它是啥东西。
而 $string_decoded 对perl来说就是有语义的字符串了,虽然他本身在perl内部是以UTF8编码的方式存储的,但是它已经被打上了标记,perl知道它是字符串,该按字符来操作,此时如果你用substr之类的函数对 $string_decoded 操作的话,便是按 “中(\xE4\xB8\xAD)”,“国(\xE5\x9B\xBD)” 两个字符来操作了,而不是在未 decode 之前,以一个字节一个字节的方式处理。

在输出的时候,我们应该仍以字节流的方式输出,因为字符只是一个概念,一个具象,它可以有不同的表现形式(不同编码的字节流),这个时候你可以根据下一个需要取得你这个输出作为输入的目标程序的要求(网络要求,编码要求),来对你的输出进行编码(成字节流),然后再传输给它。所以这个时候,你需要对需要输出的字符串进行 encode,比如:

use Encode;
$string="中国";
$string_decoded=decode_utf8($string);
$string_encoded=encode("gb2312", $string_decoded);
print $string_encoded;

这个时候, $string_encoded 中便是以 gb2312 编码方式编码过的字节流了(它同样代表“中国”这个字符串)。
如果你直接输出 $string_decoded 而不做 encode 的话,perl 便会按这个字符串在其内存中保存的方式(也就是utf8)输出,如果你是 utf8 的环境,你可以看到正确的字符串,但如果你这个字符串里面一旦包含了大于\xFF的字节,那么perl会警告"Wide character in print..."。那为什么我 encode 了这个字符串后perl不会报这个警告呢?那是因为perl会对“字符串”做标记,decode会打上标记,encode后会去掉这个标记,一旦你输出的时候有这个标记,并且有字节大于\xFF,perl就会丢出那个警告,下次你看到这个警告,一眼就可以看出是因为你程序的某个输出没有经过编码转换成字节流的缘故的。


呃。。。我是不是有点太罗嗦了。。。
Anyway, 希望大家对 Perl 的 encoding 有个了解。



2009/3/19 Okàjn <okajn.cn@gmail.com>
这么写本身就有点问题吧,encode实际是str2bytes,

$string = "出征进行曲";
代码里明文写出的字符串就是以bytes存在$string中,不应该对$string再encode


2009/3/19 Calvin <calvin.ngei@gmail.com>


你試試把下面的存為 utf8文件執行一下:

#!/usr/bin/perl
use Encode;
use Encode::Guess qw/utf8 euc-cn gbk utf-16le/;
$string="出征进行曲";
$string=encode('gbk',$string);
$decoder = guess_encoding($string);
$info=$decoder->decode($string);
print "$info\n";

On 3月19日, 下午9时24分, Okàjn <okajn...@gmail.com> wrote:
> use Encode::Guess qw/utf-8 euc-cn gbk utf-16le/;
> 改为
> use Encode::Guess qw/utf8 euc-cn gbk utf-16le/;
>
> 运行结果:
>
> Wide character in print at ./test.pl line 7.
> 出征进行曲
>
> 2009/3/19 Calvin <calvin.n...@gmail.com>
>
> > 按照網上搜索到的 Encode:;Guess 的資料,寫了個 test.pl,內容:
>
> > #!/usr/bin/perl
>
> > use Encode;
> > use Encode::Guess qw/utf-8 euc-cn gbk utf-16le/;
> > $string="出征进行曲";
> > $decoder = guess_encoding($string);
> > $info=$decoder->decode($string);
> > print "$info\n";
>
> > 這個 test.pl 保存成 utf8 txt檔案,執行,出錯:
>
> > Can't locate object method "decode" via package "utf-8-strict or
> > utf8" (perhaps you forgot to load "utf-8-strict or utf8"?) at ./
> > test.pl line 6.
>
> > 按照網上的例子和官方說明,Encode::Guess是這樣用的沒錯啊,怎麼回事呢?






--~--~---------~--~----~------------~-------~--~----~
您收到此信息是由于您订阅了 Google 论坛"PerlChina Mongers 讨论组"论坛。
 要在此论坛发帖,请发电子邮件到 perlchina@googlegroups.com
 要退订此论坛,请发邮件至 perlchina+unsubscribe@googlegroups.com
 更多选项,请通过 http://groups.google.com/group/perlchina?hl=zh-CN 访问该论坛

-~----------~----~----~----~------~----~------~--~---

没有评论: