新聞中心
本文和大家重點(diǎn)學(xué)習(xí)一下Perl Unicode全攻略,耐心看完本文,相信你今后在Perl Unicode處理上不會(huì)再有什么問題,希望你對(duì)本文介紹會(huì)感興趣。

成都創(chuàng)新互聯(lián)服務(wù)項(xiàng)目包括瓊結(jié)網(wǎng)站建設(shè)、瓊結(jié)網(wǎng)站制作、瓊結(jié)網(wǎng)頁(yè)制作以及瓊結(jié)網(wǎng)絡(luò)營(yíng)銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢(shì)、行業(yè)經(jīng)驗(yàn)、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,瓊結(jié)網(wǎng)站推廣取得了明顯的社會(huì)效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到瓊結(jié)省份的部分城市,未來相信會(huì)繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!
Perl Unicode全攻略
本文內(nèi)容適用于perl5.8及其以上版本.
perlinternalform
在Perl看來,字符串只有兩種形式.一種是octets,即8位序列,也就是我們通常說的字節(jié)數(shù)組.另一種utf8編碼的字符串,perl管它叫string.也就是說:Perl只認(rèn)識(shí)兩種編碼:Ascii(octets)和utf8(string).
utf8flag
那么perl如何確定一個(gè)字符串是octets還是utf8編碼的字符串呢?perl可沒有什么智能,他完全是靠字符串上的utf8flag.在perl內(nèi)部,字符串結(jié)構(gòu)由兩部分組成:數(shù)據(jù)和utf8flag.比如字符串"中國(guó)"在perl內(nèi)部的存儲(chǔ)是這樣:
utf8flag數(shù)據(jù)
On中國(guó)
如果utf8flag是On的話,perl就會(huì)把中國(guó)當(dāng)成utf8字符串來處理,如果utf8flag為Off,perl就會(huì)把他當(dāng)成octets來處理.所有字符串相關(guān)的函數(shù)包括正則表達(dá)式都會(huì)受utf8flag的影響.讓我們來看個(gè)例子:
程序代碼:
- useEncode;
- usestrict;
- my$str="中國(guó)";
- Encode::_utf8_on($str);
- printlength($str)."\n";
- Encode::_utf8_off($str);
- printlength($str)."\n";
運(yùn)行結(jié)果是:
程序代碼:
2
6
這里我們使用Encode模塊的_utf8_on函數(shù)和_utf8_off函數(shù)來開關(guān)字符串"中國(guó)"的utf8flag.可以看到,utf8flag打開的時(shí)候,"中國(guó)"被當(dāng)成utf8字符串處理,所以其長(zhǎng)度是2.utf8flag關(guān)閉的時(shí)候,"中國(guó)"被當(dāng)成octets(字節(jié)數(shù)組)處理,出來的長(zhǎng)度是6(我的編輯器用的是utf8編碼,如果你的編輯器用的是gb2312編碼,那么長(zhǎng)度應(yīng)該是4).
再來看看正則表達(dá)式的例子:
程序代碼:
- useEncode;
- usestrict;
- my$a="china----中國(guó)";
- my$b="china----中國(guó)";
- Encode::_utf8_on($a);
- Encode::_utf8_off($b);
- $a=~s/\W+//g;
- $b=~s/\W+//g;
- print$a,"\n";
- print$b,"\n";
運(yùn)行結(jié)果:
程序代碼:
WidecharacterinprintatPerl Unicode.plline10.
china中國(guó)
china
結(jié)果***行是一條警告,這個(gè)我們稍后再討論.結(jié)果的第二行說明,utf8flag開啟的情況下,正則表達(dá)式中的\w能夠匹配中文,反之則不能.
如何確定一個(gè)字符串的utf8flag是否已開啟?使用Encode::is_utf8($str).這個(gè)函數(shù)并不是用來檢測(cè)一個(gè)字符串是不是utf8編碼,而是僅僅看看它的utf8flag是否開啟.
eq
eq是一個(gè)字符串比較操作符,只有當(dāng)字符串的內(nèi)容一致并且utf8flag的狀態(tài)也是一致的時(shí)候,eq才會(huì)返回真.
理論就是上面這些,一定要搞明白,記清楚!下面是實(shí)際應(yīng)用.#p#
Perl Unicode轉(zhuǎn)碼
如果你有一個(gè)字符串"中國(guó)",它是gb2312編碼的.如果它的utf8flag是關(guān)閉的,它就會(huì)被當(dāng)成octets來處理,length()會(huì)返回4,這通常不是你想要的.而如果你開啟它的utf8flag,則它會(huì)被當(dāng)做utf8編碼的字符串來處理.由于它本來的編碼是gb2312的,不是utf8的,這就可能導(dǎo)致錯(cuò)誤發(fā)生.由于gb2312和utf8內(nèi)碼范圍部分重疊,所以很多時(shí)候,不會(huì)有錯(cuò)誤報(bào)出來,但是perl可能已經(jīng)錯(cuò)誤地拆解了字符.嚴(yán)重的時(shí)候,perl會(huì)報(bào)警,說某個(gè)字節(jié)不是合法的utf8內(nèi)碼.
解決的方法很顯然,如果你的字符串本來不是utf8編碼的,應(yīng)該先把它轉(zhuǎn)成utf8編碼,并且使它的utf8flag處于開啟狀態(tài).對(duì)于一個(gè)gb2312編碼的字符串,你可以使用
程序代碼:
- $str=Encode::decode("gb2312",$str);
來將其轉(zhuǎn)化為utf8編碼并開啟utf8flag.如果你的字符串編碼本來就是utf8,只是utf8flag沒有打開,那么你可以使用以下三種方式中的任一種來開啟utf8flag:
程序代碼:
- $str=Encode::decode_utf8($str);
- $str=Encode::decode("utf8",$str);
- Encode::_utf8_on($str);
***一種方式效率***,但是官方不推薦.以下劃線開頭的函數(shù)是內(nèi)部函數(shù),出于禮貌,一般不從外部調(diào)用.
字符串連接
.是字符串連接操作符.連接兩個(gè)字符串時(shí),如果兩個(gè)字符串的utf8flag都是Off,那么結(jié)果字符串也是Off.如果其中任何一個(gè)字符串的utf8flag是On的話,那么結(jié)果字符串的utf8flag將是On.連接字符串并不會(huì)改變它們?cè)瓉淼木幋a,所以如果你把兩個(gè)不同編碼的字符串連在一起,那么以后不管對(duì)這個(gè)字符串怎么轉(zhuǎn)碼,都總會(huì)有一段是亂碼.這種情況一定要避免,連接兩個(gè)字符串之前應(yīng)該確保它們編碼一致.如有必要,先進(jìn)行轉(zhuǎn)碼,再連接字符串.
Perl Unicode編程基本原則
對(duì)于任何要處理的Perl Unicode字符串,1)把它的編碼轉(zhuǎn)換成utf8;2)開啟它的utf8flag
字符串來源
為了應(yīng)用上面說到的基本原則,我們首先要知道字符串本來的編碼和utf8flag開關(guān)情況,這里我們討論幾種情況.
1)命令行參數(shù)和標(biāo)準(zhǔn)輸入.從命令行參數(shù)或標(biāo)準(zhǔn)輸入(STDIN)來的字符串,它的編碼跟locale有關(guān).如果你的locale是zh_CN或zh_CN.gb2312,那么進(jìn)來的字符串就是gb2312編碼,如果你的locale是zh_CN.gbk,那么進(jìn)來的編碼就是gbk,如果你的編碼是zh_CN.UTF8,那進(jìn)來的編碼就是utf8.不管是什么編碼,進(jìn)來的字符串的utf8flag都是關(guān)閉的狀態(tài).
2)你的源代碼里的字符串.這要看你編寫源代碼時(shí)用的是什么編碼.在editplus里,你可以通過"文件"->"另存為"查看和更改編碼.在linux下,你可以cat一個(gè)源代碼文件,如果中文正常顯示,說明源代碼的編碼跟locale是一致的.源代碼里的字符串的utf8flag同樣是關(guān)閉的狀態(tài).
如果你的源代碼里含有中文,那么你***遵循這個(gè)原則:1)編寫代碼時(shí)使用utf8編碼,2)在文件的開頭加上useutf8;語句.這樣,你源代碼里的字符串就都會(huì)是utf8編碼的,并且utf8flag也已經(jīng)打開.
3)從文件讀入.這個(gè)毫無疑問,你的文件是什么編碼,讀進(jìn)來就是什么編碼了.讀進(jìn)來以后,utf8flag是off狀態(tài).
4)抓取網(wǎng)頁(yè).網(wǎng)頁(yè)是什么編碼就是什么編碼,utf8flag是off狀態(tài).網(wǎng)站的編碼可以從響應(yīng)頭里或者h(yuǎn)tml的
標(biāo)簽里獲得.也有可能出現(xiàn)響應(yīng)頭和htmlhead里都沒說明編碼的情況,這個(gè)就是做的很不禮貌的網(wǎng)頁(yè)了.這時(shí)候只能用程序來猜:程序代碼:
- useEncode;
- useLWP::Simpleqw(get);
- usestrict;
- my$str=get"http://www.sina.com.cn";
- eval{my$str2=$str;Encode::decode("gbk",$str2,1)};
- print"notgbk:$@\n"if$@;
- eval{my$str2=$str;Encode::decode("utf8",$str2,1)};
- print"notutf8:$@\n"if$@;
- eval{my$str2=$str;Encode::decode("big5",$str2,1)};
- print"notbig5:$@\n"if$@;
輸出:
程序代碼:
- notutf8:utf8"\xD0"doesnotmaptoPerl Unicodeat/usr/local/lib/perl/5.8.8/Encode.pmline162.
- notbig5:big5-eten"\xC8"doesnotmaptoPerl Unicodeat/usr/local/lib/perl/5.8.8/Encode.pmline162.
我們給decode函數(shù)傳遞了第三個(gè)參數(shù),要求有異常字符的時(shí)候報(bào)錯(cuò).我們用eval捕獲錯(cuò)誤,轉(zhuǎn)碼失敗說明字符串本來不是這種編碼.另外注意我們每次都把$str拷貝到$str2,這是因?yàn)閐ecode第三個(gè)參數(shù)為1時(shí),decode以后,傳給它的字符串參數(shù)(第二個(gè)參數(shù)會(huì)被清空).我們拷貝一下,這樣每次被清空的都是$str2,$str不變.
來看結(jié)果,既然不是utf8,也不是big5,那就應(yīng)該是gbk了.對(duì)于其他不知編碼的字符串,也可以使用這種方法來猜.不過因?yàn)閹追N編碼的內(nèi)碼范圍都差不多,所以如果字符串比較短,就可能出不了異常字符,所以這個(gè)方法只適用于大段的文字.
輸出
字符串在程序內(nèi)被正確地處理后,要展現(xiàn)給用戶.這時(shí)我們需要把字符串從perlinternalform轉(zhuǎn)化成用戶能接受的形式.簡(jiǎn)單地說,就是把字符串從utf8編碼轉(zhuǎn)換成輸出的編碼或表現(xiàn)界面的編碼.這時(shí)候,我們使用$str=Encode::encode('charset',$str);.同樣可以分為幾種情況.
1)標(biāo)準(zhǔn)輸出.標(biāo)準(zhǔn)輸出的編碼跟locale一致.輸出的時(shí)候utf8flag應(yīng)該關(guān)閉,不然就會(huì)出現(xiàn)我們前面看到的那行警告:
程序代碼:
- WidecharacterinprintatPerl Unicode.plline10.
2)GUI程序.這個(gè)應(yīng)該是不用干什么,utf8編碼,utf8flag開啟就行.沒有實(shí)際測(cè)試過.
3)做httppost.看網(wǎng)頁(yè)表單要求什么編碼.utf8flag開或關(guān)無所謂,因?yàn)閔ttppost發(fā)送出去的只是字符串中的數(shù)據(jù)部分,不管utf8flag. #p#
PerlIO
PerlIO為我們的輸入/輸出轉(zhuǎn)碼提供了便利.它可以針對(duì)某個(gè)文件句柄,輸入的時(shí)候自動(dòng)幫你轉(zhuǎn)碼并開啟utf8flag,輸出的時(shí)候,自動(dòng)幫你轉(zhuǎn)碼并關(guān)閉utf8flag.假設(shè)你的終端locale是gb2312,看下面的例子:
程序代碼:
- usestrict;
- binmode(STDIN,":encoding(gb2312)");
- binmode(STDOUT,":encoding(gb2312)");
- while(<>){
- chomp;
- print$_,length,"\n";
- }
運(yùn)行后輸入"中國(guó)",結(jié)果:
程序代碼:
中國(guó)2
這樣我們就省去了輸入和輸出時(shí)轉(zhuǎn)碼的麻煩.PerlIO可以作用于任何文件句柄,具體請(qǐng)參考perldocPerlIO.
相關(guān)API
都是Encode模塊的:
$octets=encode(ENCODING,$string[,CHECK])把字符串從utf8編碼轉(zhuǎn)成指定的編碼,并關(guān)閉utf8flag.
$string=decode(ENCODING,$octets[,CHECK])把字符串從其他編碼轉(zhuǎn)成utf8編碼,并開啟utf8flag,不過有個(gè)例外就是,如果字符串是僅僅ascii編碼或EBCDIC編碼的話,不開啟utf8flag.
is_utf8(STRING[,CHECK])看看utf8flag是否開啟.如果第二個(gè)參數(shù)為真,則同時(shí)檢查編碼是否符合utf8.這個(gè)檢測(cè)不一定準(zhǔn)確,跟decode方式檢測(cè)效果一樣.
_utf8_on(STRING)打開字符串的utfflag
_utf8_off(STRING)關(guān)閉字符串的utfflag
***兩個(gè)是內(nèi)部函數(shù),不推薦使用.
參考Perl Unicode
utf8和utf-8
前面我們提到的一直都是utf8.在perl中,utf8和utf-8是不一樣的.utf-8是指國(guó)際上標(biāo)準(zhǔn)的utf-8定義,而utf8是perl在國(guó)際標(biāo)準(zhǔn)上做了一些擴(kuò)展,能兼容的內(nèi)碼要比國(guó)際標(biāo)準(zhǔn)的多一些.perlinternalform使用的是utf8.另外順便提一下,字符集的名稱是不區(qū)分大小寫的并且"_"和"-"是等價(jià)的.
EBCDIC
EBCDIC是一套遺留的寬字符解決方案,不同于Perl Unicode,它不是Ascii的超集.上面介紹的方案并不完全適用于EBCDIC.關(guān)于EBCDIC,請(qǐng)參考perldocperlebcdic
當(dāng)前文章:PerlUnicode全程攻略
分享鏈接:http://www.5511xx.com/article/djipogi.html


咨詢
建站咨詢
