Perl Unicode 全攻略:

来源:互联网 发布:淘宝美式画 编辑:程序博客网 时间:2024/06/06 15:02
Perl Unicode 全攻略:耐心看完本文,相信你今后在unicode处理上不同再有问题:在Perl看来,字符串只有两种形式。一种是octets,即8位序列,也就是我们通常说的字节数组另一种utf8 编码的字符串,perl 管它叫string.也就是说:Perl 只认识两种编码:ascii(octets) 和utf8 (字符串)utf8 flag:那么 perl 如何却动一个字符串是octets还是utf8编码的字符串呢?perl 可没有什么智能,它完全是靠字符串的utf8 flag.在perl 内部,字符串结构由两部分组成:数据和utf8 flag,比如字符串"中国"在perl内部的存储是这样:utf8 flag     数据On            中国如果 utf8 flag 是on的话,perl 就会把中国当成utf8 字符串来处理,如果 utf8 flag 为off,perl就会把他当成octets来处理。所有的字符串相关的函数包括正则表达式都会受utf8 flag的影响,让我们来看个例子[root@jxglapp1 pfwx-master]# cat mojo.pluse lib "./lib";use mojo::Client;use Data::Dumper;use Mojolicious::Lite;use JSON qw/encode_json decode_json/;  use Encode;no strict;no warnings;use JSON; use POSIX;use JSON::RPC::Client;use Data::Dumper;use URI::Escape;my $client = mojo::Client->new();  print Dumper($client);  get '/api/SMSsendx' => sub {   my $c = shift;   my $sourceip=$c->param('sourceip');   my $message = $c->param('message');      print "Length==";      print length($message)."\n";       print "\$message is $message\n";      sleep 30;  app->start;  [root@jxglapp1 pfwx-master]# vim mojo.pl[root@jxglapp1 pfwx-master]# morbo mojo.plServer available at http://127.0.0.1:3000$VAR1 = bless( {                 'client_version' => '1.0'               }, 'mojo::Client' );[Mon Mar 13 08:23:47 2017] [debug] GET "/api/SMSsendx"[Mon Mar 13 08:23:47 2017] [debug] Routing to a callbackLength==2$message is 中国$flag===1------------------------------------------------------------[oracle@oadb utf-8]$ cat a3.pl use Encode;use strict;my $str = "中国";print length($str);print "\n";Encode::_utf8_on($str);print length($str) . "\n";Encode::_utf8_off($str);print length($str) . "\n";[oracle@oadb utf-8]$ perl a3.pl 626这里我们使用Encode模块的_utf8_on 函数和_utf8_off 函数来开关字符串"中国"的utf8 flag.可以看到,utf8 flag打开的时候,"中国"被当成utf8 字符串处理,所以其长度为2.utf8 flag关闭的时候,"中国"被当成octets(字节数组)处理,出来的长度为6在看看正则表达式:[oracle@oadb utf-8]$ cat a4.pl use Encode;use strict;my $a = "1中国2";print "\$a is $a\n";print length($a)."\n";$a =~ s/\W+//g;print "\$a is $a\n";[oracle@oadb utf-8]$ perl a4.pl $a is 1中国28$a is 12[oracle@[oracle@oadb utf-8]$ cat a4.pl use Encode;use strict;my $a = "1中国2";Encode::_utf8_off($a);print "\$a is $a\n";print length($a)."\n";$a =~ s/\W+//g;print "\$a is $a\n";[oracle@oadb utf-8]$ perl a4.pl $a is 1中国28$a is 12[oracle@oadb utf-8]$ cat a4.pl use Encode;use strict;my $a = "1中国2";Encode::_utf8_on($a);print "\$a is $a\n";print length($a)."\n";$a =~ s/\W+//g;print "\$a is $a\n";[oracle@oadb utf-8]$ perl a4.pl Wide character in print at a4.pl line 7.$a is 1中国24Wide character in print at a4.pl line 12.$a is 1中国2此时匹配不到:如何确定一个字符串的utf8 flag 是否开启?使用Encode::is_utf8($str)这个函数并不是用来检测一个字符串是不是utf8 编码,而是仅仅看看它的utf8 flag是否开启[oracle@oadb utf-8]$ cat a4.pl use Encode;use strict;my $a = "1中国2";#Encode::_utf8_on($a);print "\$a is $a\n";print length($a)."\n";$a =~ s/\W+//g;print "\$a is $a\n";my $flag=Encode::is_utf8($a);print "\$flag is $flag\n";[oracle@oadb utf-8]$ perl a4.pl$a is 1中国28$a is 12$flag is[oracle@oadb utf-8]$ cat a4.pl use Encode;use strict;my $a = "1中国2";Encode::_utf8_on($a);print "\$a is $a\n";print length($a)."\n";$a =~ s/\W+//g;print "\$a is $a\n";my $flag=Encode::is_utf8($a);print "\$flag is $flag\n";[oracle@oadb utf-8]$ perl a4.pl Wide character in print at a4.pl line 7.$a is 1中国24Wide character in print at a4.pl line 12.$a is 1中国2$flag is 1unicode 转码:如果你有一个字符串"中国",它是gb2312编码的。如果它的utf-8 flag是关闭的,它就会被当成octets来处理,length()会返回4,这通常不是你想要的。而 如果你开启它的utf8 flag,则它会被当做utf8 编码的字符串来处理。由于它本来的编码是gb2312的,不是utf-8的,这就可能导致错误发生。解决的方法很显然,如果你的字符串本来不是utf8编码的,应该先把它转成utf8编码,并且使它的utf8 flag处于开启状态。对于一个gb2312编码的字符串,你可以使用:程序代码:$str = Encode::decode("gb2312", $str);字符串连接:. 是字符串连接操作符,连接两个字符串时,如果两个字符串的utf8 flag都是off,那么结果字符串也是off。如果其中任何一个字符串的utf8 flag是on的话,那么结果字符串的utf8 flag将是on.perl unicode编程基本原则对于任何要处理的unicode 字符串, 1)把它的编码转换成utf8 2) 开启它的utf8 flag字符串来源:为了应用上面说到的基本原则,我们首选要知道字符串本来的编码和utf8 flag开关情况,这里我们讨论几种情况:1) 命令行参数和标准输入。 从命令行参数或标准输入(STDIN)来的字符串, 它的编码跟locale有关。 如果你的locale是zh_CN或zh_CN.gb2312, 那么进来的字符串就是gb2312编码, 如果你的locale是zh_CN.gbk, 那么进来的编码就是gbk, 如果你的编码是zh_CN.UTF8, 那进来的编码就是utf8。 不管是什么编码, 进来的字符串的utf8 flag都是关闭的状态。2)你的源代码里的字符串。 这要看你编写源代码用的是什么编码,在editplus里, 你可以通过“文件”->“另存为”查看和更改编码。 在linux下, 你可以cat一个源代码文件, 如果中文正常显示, 说明源代码的编码跟locale是一致的。源代码里的字符串的utf8 flag同样是关闭的状态。如果你的源代码里含有中文, 那么你最好遵循这个原则: 1) 编写代码时使用utf8编码, 2)在文件的开头加上“use utf8;”语句。这样, 你源代码里的字符串就都会是utf8编码的, 并且utf8 flag也已经打开。

0 0