perl編碼,字節流和字符

本人最近在linux上做開發遇到了發送郵件亂碼的問題,這篇文章給了我一些提示,最終解決了。特此轉載一下

摘自互聯網,未加整理。

需要分清楚“字符(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就會丟出那個警告,下次你看到這個警告,一眼就可以看出是因爲你程序的某個輸出沒有經過編碼轉換成字節流的緣故的。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章