欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
扶凱 ? Perl Unicode全攻略(轉)

Perl Unicode全攻略(轉)

Dec 13th, 2008

轉載本站文章請注明,轉載自:扶凱[http://www.php-oa.com]

本文鏈接: http://www.php-oa.com/2008/12/13/perl-unicode.html

轉自:http://blog.chinaunix.net/u2/70049/showart_1210487.html

耐心看完本文, 相信你今后在unicode處理上不會(huì )再有什么問(wèn)題.

本文內容適用于perl 5.8及其以上版本.

perl internal form
在Perl看來(lái), 字符串只有兩種形式. 一種是octets, 即8位序列, 也就是我們通常說(shuō)的字節數組. 另一種utf8編碼的字符串, perl管它叫string. 也就是說(shuō): Perl只認識兩種編碼: Ascii(octets)和utf8(string).

utf8 flag

那么perl如何確定一個(gè)字符串是octets還是utf8編碼的字符串呢? perl可沒(méi)有什么智能, 他完全是靠字符串上的utf8 flag. 在perl內部, 字符串結構由兩部分組成: 數據和utf8 flag. 比如字符串"中國"在perl內部的存儲是這樣:

utf8 flag    數據
On   中國

如果utf8 flag是On的話(huà), perl就會(huì )把中國當成utf8字符串來(lái)處理, 如果utf8 flag為Off, perl就會(huì )把他當成octets來(lái)處理. 所有字符串相關(guān)的函數包括正則表達式都會(huì )受utf8 flag的影響. 讓我們來(lái)看個(gè)例子:

程序代碼:
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函數來(lái)開(kāi)關(guān)字符串"中國"的utf8 flag. 可以看到, utf8 flag打開(kāi)的時(shí)候, "中國"被當成utf8字符串處理, 所以其長(cháng)度是2. utf8 flag關(guān)閉的時(shí)候, "中國"被當成octets(字節數組)處理, 出來(lái)的長(cháng)度是6(我的編輯器用的是utf8編碼, 如果你的編輯器用的是gb2312編碼, 那么長(cháng)度應該是4).

再來(lái)看看正則表達式的例子:

程序代碼:
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

結果第一行是一條警告, 這個(gè)我們稍后再討論. 結果的第二行說(shuō)明, utf8 flag開(kāi)啟的情況下, 正則表達式中的\w能夠匹配中文, 反之則不能.

如何確定一個(gè)字符串的utf8 flag是否已開(kāi)啟? 使用Encode::is_utf8($str). 這個(gè)函數并不是用來(lái)檢測一個(gè)字符串是不是utf8編碼, 而是僅僅看看它的utf8 flag是否開(kāi)啟.

eq

eq是一個(gè)字符串比較操作符, 只有當字符串的內容一致并且utf8 flag的狀態(tài)也是一致的時(shí)候, eq才會(huì )返回真.

理論就是上面這些, 一定要搞明白, 記清楚! 下面是實(shí)際應用.

unicode轉碼

如果你有一個(gè)字符串"中國", 它是gb2312編碼的. 如果它的utf8 flag是關(guān)閉的, 它就會(huì )被當成octets來(lái)處理, length()會(huì )返回4, 這通常不是你想要的. 而如果你開(kāi)啟它的utf8 flag, 則它會(huì )被當做utf8編碼的字符串來(lái)處理. 由于它本來(lái)的編碼是gb2312的, 不是utf8的, 這就可能導致錯誤發(fā)生. 由于gb2312和utf8內碼范圍部分重疊, 所以很多時(shí)候, 不會(huì )有錯誤報出來(lái), 但是perl可能已經(jīng)錯誤地拆解了字符. 嚴重的時(shí)候, perl會(huì )報警, 說(shuō)某個(gè)字節不是合法的utf8內碼.

解決的方法很顯然, 如果你的字符串本來(lái)不是utf8編碼的, 應該先把它轉成utf8編碼, 并且使它的utf8 flag處于開(kāi)啟狀態(tài). 對于一個(gè)gb2312編碼的字符串, 你可以使用

程序代碼:
$str = Encode::decode("gb2312", $str);

來(lái)將其轉化為utf8編碼并開(kāi)啟utf8 flag. 如果你的字符串編碼本來(lái)就是utf8, 只是utf8 flag沒(méi)有打開(kāi), 那么你可以使用以下三種方式中的任一種來(lái)開(kāi)啟utf8 flag:

程序代碼:
$str = Encode::decode_utf8($str);
$str = Encode::decode("utf8", $str);
Encode::_utf8_on($str);

最后一種方式效率最高, 但是官方不推薦. 以下劃線(xiàn)開(kāi)頭的函數是內部函數, 出于禮貌, 一般不從外部調用.

字符串連接

. 是字符串連接操作符. 連接兩個(gè)字符串時(shí), 如果兩個(gè)字符串的utf8 flag都是Off, 那么結果字符串也是Off. 如果其中任何一個(gè)字符串的utf8 flag是On的話(huà), 那么結果字符串的utf8 flag將是On. 連接字符串并不會(huì )改變它們原來(lái)的編碼, 所以如果你把兩個(gè)不同編碼的字符串連在一起, 那么以后不管對這個(gè)字符串怎么轉碼, 都總會(huì )有一段是亂碼. 這種情況一定要避免, 連接兩個(gè)字符串之前應該確保它們編碼一致. 如有必要, 先進(jìn)行轉碼, 再連接字符串.

perl unicode編程基本原則

對于任何要處理的unicode字符串, 1)把它的編碼轉換成utf8; 2)開(kāi)啟它的utf8 flag

字符串來(lái)源

為了應用上面說(shuō)到的基本原則, 我們首先要知道字符串本來(lái)的編碼和utf8 flag開(kāi)關(guān)情況, 這里我們討論幾種情況.

1) 命令行參數和標準輸入. 從命令行參數或標準輸入(STDIN)來(lái)的字符串, 它的編碼跟locale有關(guān). 如果你的locale是zh_CN或zh_CN.gb2312, 那么進(jìn)來(lái)的字符串就是gb2312編碼, 如果你的locale是zh_CN.gbk, 那么進(jìn)來(lái)的編碼就是gbk, 如果你的編碼是zh_CN.UTF8, 那進(jìn)來(lái)的編碼就是utf8. 不管是什么編碼, 進(jìn)來(lái)的字符串的utf8 flag都是關(guān)閉的狀態(tài).

2) 你的源代碼里的字符串. 這要看你編寫(xiě)源代碼時(shí)用的是什么編碼. 在editplus里, 你可以通過(guò)"文件"->"另存為"查看和更改編碼. 在linux下, 你可以cat一個(gè)源代碼文件, 如果中文正常顯示, 說(shuō)明源代碼的編碼跟locale是一致的. 源代碼里的字符串的utf8 flag同樣是關(guān)閉的狀態(tài).

如果你的源代碼里含有中文, 那么你最好遵循這個(gè)原則: 1) 編寫(xiě)代碼時(shí)使用utf8編碼, 2)在文件的開(kāi)頭加上use utf8;語(yǔ)句. 這樣, 你源代碼里的字符串就都會(huì )是utf8編碼的, 并且utf8 flag也已經(jīng)打開(kāi).

3) 從文件讀入. 這個(gè)毫無(wú)疑問(wèn), 你的文件是什么編碼, 讀進(jìn)來(lái)就是什么編碼了. 讀進(jìn)來(lái)以后, utf8 flag是off狀態(tài).

4) 抓取網(wǎng)頁(yè). 網(wǎng)頁(yè)是什么編碼就是什么編碼, utf8 flag是off狀態(tài). 網(wǎng)站的編碼可以從響應頭里或者html的<head>標簽里獲得. 也有可能出現響應頭和html head里都沒(méi)說(shuō)明編碼的情況, 這個(gè)就是做的很不禮貌的網(wǎng)頁(yè)了. 這時(shí)候只能用程序來(lái)猜:

程序代碼:
use Encode;
use LWP::Simple qw(get);
use strict;

my $str = get "http://www.sina.com.cn";

eval {my $str2 = $str; Encode::decode("gbk", $str2, 1)};
print "not gbk: $@\n" if $@;

eval {my $str2 = $str; Encode::decode("utf8", $str2, 1)};
print "not utf8: $@\n" if $@;

eval {my $str2 = $str; Encode::decode("big5", $str2, 1)};
print "not big5: $@\n" if $@;

輸出:

程序代碼:
not utf8: utf8 "\xD0" does not map to Unicode at /usr/local/lib/perl/5.8.8/Encode.pm line 162.

not big5: big5-eten "\xC8" does not map to Unicode at /usr/local/lib/perl/5.8.8/Encode.pm line 162.

我們給decode函數傳遞了第三個(gè)參數, 要求有異常字符的時(shí)候報錯. 我們用eval捕獲錯誤, 轉碼失敗說(shuō)明字符串本來(lái)不是這種編碼. 另外注意我們每次都把$str拷貝到$str2, 這是因為decode第三個(gè)參數為1時(shí), decode以后, 傳給它的字符串參數(第二個(gè)參數會(huì )被清空). 我們拷貝一下, 這樣每次被清空的都是$str2, $str不變.

來(lái)看結果, 既然不是utf8, 也不是big5, 那就應該是gbk了. 對于其他不知編碼的字符串, 也可以使用這種方法來(lái)猜. 不過(guò)因為幾種編碼的內碼范圍都差不多, 所以如果字符串比較短, 就可能出不了異常字符, 所以這個(gè)方法只適用于大段的文字.

輸出

字符串在程序內被正確地處理后, 要展現給用戶(hù). 這時(shí)我們需要把字符串從perl internal form轉化成用戶(hù)能接受的形式. 簡(jiǎn)單地說(shuō), 就是把字符串從utf8編碼轉換成輸出的編碼或表現界面的編碼. 這時(shí)候, 我們使用$str = Encode::encode(‘charset’, $str);. 同樣可以分為幾種情況.

1) 標準輸出. 標準輸出的編碼跟locale一致. 輸出的時(shí)候utf8 flag應該關(guān)閉, 不然就會(huì )出現我們前面看到的那行警告:

程序代碼:
Wide character in print at unicode.pl line 10.

2) GUI程序. 這個(gè)應該是不用干什么, utf8編碼, utf8 flag開(kāi)啟就行. 沒(méi)有實(shí)際測試過(guò).

3) 做http post. 看網(wǎng)頁(yè)表單要求什么編碼. utf8 flag開(kāi)或關(guān)無(wú)所謂, 因為http post發(fā)送出去的只是字符串中的數據部分, 不管utf8 flag.

PerlIO

PerlIO為我們的輸入/輸出轉碼提供了便利. 它可以針對某個(gè)文件句柄, 輸入的時(shí)候自動(dòng)幫你轉碼并開(kāi)啟utf8 flag, 輸出的時(shí)候, 自動(dòng)幫你轉碼并關(guān)閉utf8 flag. 假設你的終端locale是gb2312, 看下面的例子:

程序代碼:
use strict;
binmode(STDIN, ":encoding(gb2312)");
binmode(STDOUT, ":encoding(gb2312)");
while (<>) {
chomp;
print $_, length, "\n";
}

運行后輸入"中國", 結果:

程序代碼:
中國2

這樣我們就省去了輸入和輸出時(shí)轉碼的麻煩. PerlIO可以作用于任何文件句柄, 具體請參考perldoc PerlIO.

相關(guān)API

都是Encode模塊的:

$octets = encode(ENCODING, $string [, CHECK]) 把字符串從utf8編碼轉成指定的編碼, 并關(guān)閉utf8 flag.

$string = decode(ENCODING, $octets [, CHECK]) 把字符串從其他編碼轉成utf8編碼, 并開(kāi)啟utf8 flag, 不過(guò)有個(gè)例外就是, 如果字符串是僅僅ascii編碼或EBCDIC編碼的話(huà), 不開(kāi)啟utf8 flag.

is_utf8(STRING [, CHECK]) 看看utf8 flag是否開(kāi)啟. 如果第二個(gè)參數為真, 則同時(shí)檢查編碼是否符合utf8. 這個(gè)檢測不一定準確, 跟decode方式檢測效果一樣.

_utf8_on(STRING) 打開(kāi)字符串的utf flag

_utf8_off(STRING) 關(guān)閉字符串的utf flag

最后兩個(gè)是內部函數, 不推薦使用.

參考perldoc Encode.

utf8和utf-8

前面我們提到的一直都是utf8. 在perl中, utf8和utf-8是不一樣的. utf-8是指國際上標準的utf-8定義, 而utf8是perl在國際標準上做了一些擴展, 能兼容的內碼要比國際標準的多一些. perl internal form使用的是utf8. 另外順便提一下, 字符集的名稱(chēng)是不區分大小寫(xiě)的并且"_"和"-"是等價(jià)的.

EBCDIC

EBCDIC是一套遺留的寬字符解決方案, 不同于unicode, 它不是Ascii的超集. 上面介紹的方案并不完全適用于EBCDIC. 關(guān)于EBCDIC, 請參考perldoc perlebcdic

 

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
黃聰:解決python中文處理亂碼,先要弄懂“字符”和“字節”的差別
decode和encode
python的str,unicode對象的encode和decode方法(轉)
Python 字符編碼轉換要訣
小結Python的中文處理
第四章 python3 語(yǔ)法基礎之字符集編碼格式
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久