日期:2014-05-17  浏览次数:20830 次

perl utf8 encoding decoding HTML::Entities Perl中字符串编码的处理

转自:http://hi.baidu.com/youzhch/blog/item/991ad4357baeb00491ef3965.html

#!/usr/bin/perl -w
use CGI;
use Encode;
use HTML::Entities;
use utf8;
$query = new CGI;

?

?

print $query->header(? -charset=>'utf-8' );?

$a = $query->param('word');
my $a = decode("utf8", $a);?? # make a string? utf

$b = encode_entities($a);

?


#$secretword = $query->param('word');
$remotehost = $query->remote_host();

$secretword = encode_entities($secretword);


#$a = "utf8 &#xHHHH ????????????????????????????? 中文 行(ゆ)こう行こうみんなわくわく";
#$b = encode_entities($a);

#print $secretword."\n";??? #输出中文? 在浏览器里显示为“中文”

print $a."\n";
print $b.$b."\n";??? #输出中文? 在浏览器里显示为“中文”
#$b =~ s/&/&/g;
#print $b."\n";??? #输出中文? 在浏览器里显示为中文

?

print<<"[HTML]";???????????????
??

<form name="f1" method="post" action="utf8hhhh.pl">
? <p>word: <input name="word" type="text" value="$b">?
?<input type="submit" name="Submit" value=" 查询 "></p>

</form><br>
$b??? #输出&#x4E2D;&#x6587;? 在浏览器里显示为“中文”
[HTML]

?

?


?

###########

?这种东西还真的少有人写,其实是转换成16进制的,研究后把代码贴给你,希望给你有用,也给后人做参考(代码部分请保存为UTF8格式,为便于显示,控制台输出我指定为GB2312),如果格式为GB2312,需要加载Encode模块,使用语句encode("utf-8", decode("gb2312", $str))进行转换。

#!/usr/bin/perl
$|=1;
use URI::Escape qw(uri_escape_utf8);
#? use encoding 'utf8', STDIN=>'utf8', STDOUT=>'gb2312';? #? original code
use encoding 'utf8', STDIN=>'utf8', STDOUT=>'utf8';
my $str="~~我有一所房子,面朝大海,春暖花开...";
for my $i(0..length($str)-1) {
?if (ord(substr($str,$i,1))<0xFF){
? print substr($str,$i,1);
?} else {
? print sprintf("&#x%1x;",ord(substr($str,$i,1)));
?}
}

?

#################Perl中字符串编码的处理

在Perl看来, 字符串只有两种形式. 一种是octets, 即8位序列, 也就是我们通常说的字节数组. 另一种utf8编码的字符串, perl管它叫string. 也就是说: Perl只熟悉两种编码: Ascii(octets)和utf8(string).

utf8 flag
在perl内部, 字符串结构由两部分组成: 数据和utf8 flag. 比如字符串"中国"在perl内部的存储是这样:
utf8 flag 数据
On 中国
假如utf8 flag是On的话, perl就会把中国当成utf8字符串来处理, 假如utf8 flag为Off, perl就会把他当成octets来处理. 所有字符串相关的函数包括正则表达式都会受utf8 flag的影响. 让我们来看个例子:
程序代码:
use Encode;
use strict;
my $str = "中国";
Encode::_utf8_on($str);
print length($str) . "\n";
Encode::_utf8_off($str);
print length($str) . "\n";
运行结果是:
程序代码:
2
6
这里我们使用Encode模块的_utf8_on函数和_utf8_off函数来开关字符串"中国"的utf8 flag. 可以看到, utf8 flag打开的时候, "中国"被当成utf8字符串处理, 所以其长度是2. utf8 flag关闭的时候, "中国"被当成octets(字节数组)处理, 出来的长度是6(我的编辑器用的是utf8编码, 假如你的编辑器用的是gb2312编码, 那么长度应该是4).

再来看看正则表达式的例子:
程序代码:
use Encode;
use strict;
my $a = "china----中国";
my $b = "china----中国";
Encode::_utf8_on($a);
Encode::_utf8_off($b);
$a =~ s/\W //g;
$b =~ s/\W //g;
print $a, "\n";
print $b, "\n";
运行结果:
程序代码:
Wide character in print at unicode.pl line 10.
china中国
china
结果第一行是一条警告, 这个我们稍后再讨论. 结果的第二行说明, utf8 flag开启的情况下, 正则表达式中的\w能够匹配中文, 反之则不能.
如何确定一个字符串的utf8 flag是否已开启? 使用Encode::is_utf8($str). 这个函数并不是用来检测一个字符串是不是utf8编码, 而是仅仅看看它的utf8 flag是否开启.

eq是一个字符串比较操作符, 只有当字符串的内容一致并且utf8 flag的状态也是一致的时候, eq才会返回真.

unicode转码
假如你有一个字符串"中国", 它是gb2312编码的. 假如它的utf8 flag是关闭的, 它就会被当成octets来处理, length()会返回4, 这通常不是你想要的. 而假如你开启它的utf8 flag, 则它会被当做utf8编码的字符串来处理. 由于它本来的编码是gb2312的, 不是utf8的, 这就可能导致错误发生. 由于gb2312和utf8内码范围部分重叠, 所以很多时候, 不会有错误报出来, 但是perl可能已经错误地拆解了字符. 严重的时候, perl会报警, 说某个字节不是合法的utf8内码.
解决的方法很显然, 假如你的字符串本来不是utf8编码的, 应该先把它转成utf8编码, 并且使它的utf8 flag处于开启状态. 对于一个gb2312编码的字符串, 你可以使用
程序代码:
$str = Encode::decode("gb2312", $str);
来将其转化为utf8编码并开启utf8 flag. 假如你的字符串编码本来就是utf8, 只是utf8 flag没有打开, 那么你可以使用以下三种方式中的任一种来开启utf8 fla