perl中字符串編碼分析和注意事項

》在 Perl看來, 字符串只有兩種形式. 一種是octets, 即8位序列, 也就是咱們一般說的字節數組. 另外一種utf8編碼的字符串, perl管它叫string. 也就是說: Perl只熟悉兩種編碼: Ascii(octets)和utf8(string).php

perl內部字符串由flag標誌位和數據區兩部分組成,其存儲結構以下:css

這裏寫圖片描述

  1. 假如utf8 flag是On perl就會把數據區內容當成utf8字符串來處理;
  2. 假如utf8 flag是Off, perl就會把數據區內容當成octets來處理. 即字節來處理;

全部字符串相關的函數包括正則表達式、文件檢測、都會受utf8 flag的影響。在默認狀況下,utf8 flag標誌位是off狀態,當咱們在代碼中使用了 use utf8 ,則表明flag標誌位是on狀態,在當前詞法範圍內都是有效的。html

Encode中的is_utf8函數能夠用於檢測當前flag開啓狀況,1表明on 0表明off;如下代碼均是使用notepad++進行編碼,字符編碼格式選擇UTF-8格式。linux


編碼格式轉換

若要進行不一樣編碼之間的轉換,可使用Encode模塊中的decode函數和encode函數,這兩個函數使用以下正則表達式

$octets = encode(ENCODING, STRING);
將標量字符串STRING從perl內部格式編碼成ENCODING格式,而且返回字節流序列。數組

For example, to convert a string from Perl's internal format into ISO-8859-1:
$octets = encode("iso-8859-1", $string);

$string = decode(ENCODING, OCTETS);
以ENCODING編碼格式從字節流中解讀字符信息,並轉化爲perl內部格式編碼。 markdown

For example, to convert ISO-8859-1 data into a string in Perl's internal format:
$string = decode("iso-8859-1", $octets);

下面展現gbk和utf8之間的相互轉碼,兩種編碼格式須要通過perl內部編碼格式:less

這裏寫圖片描述

若待編碼的字符串已是perl內部編碼格式(flag on +utf8編碼),則能夠直接進行編碼或者解碼,不須要按照上述的過程進行。函數

例子1:測試

use Encode;

#當前關閉
print "utf8 flag is 0ff\n" if !Encode::is_utf8($string1);

my $string1 = "你好";//是utf8格式,若不編碼屏幕輸出亂碼
print Encode::encode("gbk",Encode::decode("utf8",$string1)),"\n";

#flag是off狀態,看成字節來處理,長度爲6
print "length:",length($string1),"\n";

運行結果:

這裏寫圖片描述

例子2:

print "***********utf8 flag is on***************\n";
#此後utf8 flag 爲on
use utf8;

my $string2 = "你好";

#當前on
print "utf8 flag is on\n" if Encode::is_utf8($string2);

#這裏$string2至關因而內部格式了 flag is on and utf8 format
#能夠直接編碼,不用先解碼後編碼了
print Encode::encode("gbk",$string2),"\n";

#看成string來處理,長度爲2
print "length:",length($string2),"\n\n\n\n";

運行結果:

這裏寫圖片描述


注意事項

咱們在使用perl中的文件測試符-e -s -f或者系統命令copy函數時,均要求這些函數的入參或者變量是gbk編碼格式,不然會致使不符合預期的編碼結果,舉例以下:

我在目錄下這個路徑下建立了txt文件「E:\perl\文件夾1\log.txt」,不一樣的編碼格式答案是不符合預期的。

例子3:

print "**********file test and system copy attentions**************\n";
#文件測試或者調用系統copy函數等函數時 均須要使用gbk編碼

my $src1 = "E:\\perl\\文件夾1\\log.txt";
my $src2 = "E:\\perl\\文件夾1\\log.txt";
#$src2字符串flag標誌位是on,而且自己是utf8編碼,
#所以$src2是perl內部格式,能夠轉爲國標
my $gbk_src = Encode::encode("gbk", $src2);

print "gbk encode:$gbk_src\n";

#文件存在 則打印
if (-e $gbk_src){
    print "it exists\n";
}
#文件不存在 則打印
unless (-e $src){
    print "it don't exist\n";
}

運行結果:

這裏寫圖片描述

字符串來源

爲了可以正確的進行字符串編解碼, 咱們首先要知道字符串原本的編碼和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也已經打開.
  3. 從文件讀入. 這個毫無疑問, 你的文件是什麼編碼, 讀進來就是什麼編碼了. 讀進來之後, utf8 flag是off狀態.
  4. 抓取網頁. 網頁是什麼編碼就是什麼編碼, utf8 flag是off狀態. 網站的編碼能夠從響應頭裏或者html

字符轉碼API

#接口API
sub convert_utf8_to_gbk{

    my ($utf8) = @_;
    my $gbk = "";

    if (Encode::is_utf8($utf8)){
        $gbk = Encode::encode('gbk',$utf8);
    }
    else{
        $gbk = Encode::encode('gbk',Encode::decode('utf8',$utf8));
    }

    return $gbk;
}

sub convert_gbk_to_utf8{

    my ($gbk) = @_;
    my $utf8 = "";

    $utf8 = Encode::decode('gbk',$gbk);

    return $utf8;
}

#測試用例
print convert_utf8_to_gbk("你好 中國!!\n"),"\n";

print "input:";
chomp( my $input = <STDIN>);

print "output:",convert_utf8_to_gbk(convert_gbk_to_utf8($input)),"\n";

運行結果:

這裏寫圖片描述
參考入下資料:
http://blog.csdn.net/c_base_jin/article/details/78768591

相關文章
相關標籤/搜索