perl檔案編碼處理問題

2021-06-17 16:49:29 字數 3945 閱讀 1856

在看perl時,發現檔案編碼處理問題不是很懂。bg了下,發現還是有點東東,so,收藏下:

--------------------------1-----------------------------------

乙個指令碼用於分析應用程式的日誌,但是在這些日誌檔案中,有的編碼是utf-8的,有的編碼是gbk的.對於utf-8的日誌檔案,需要將內容轉換成gbk的編碼,這樣看到的中文才不至於亂碼:

因此,在perl指令碼中加入以下行判斷日誌內容,如是不是gbk的編碼,就對其轉碼:

$line=encode ("gbk",decode("utf-8",$line)) unless (detect($line) =~ /gb/);

這裡用到的模組有:

use encode;

use encode::cn;

use encode::detect::detector;

perl5.8中讀取其他編碼的文字檔案

通過改變perlio層的編碼即可實現,配合encoding指示符可以使操作過程更為自然,如讀取utf-16編碼的文字檔案:

use encoding 'gbk';                            # 系統預設編碼為gbk

use open in=>':encoding(utf16)';       # 讀入檔案時認為資料按utf-16編碼,自動根據bom頭判斷是le還是be

open(fh,"test.txt") or die;

while()

也可以用open的3引數形式指定單個檔案控制代碼的perlio層編碼,並在輸出時手工轉換編碼:

use encode;                                     # 需要使用encode函式實現手工轉碼

open(fh,"<:encoding(utf16)","test.txt") or die;        # 指定fh控制代碼的資料為utf-16編碼

while()

另外使用binmode可以隨時切換某個檔案控制代碼的perlio層編碼,如:

binmode(fh,":encoding(utf16)");     # 將fh的資料編碼置為utf-16

binmode(fh,":raw");                         # 不對fh的資料進行編譯碼處理

binmode(fh,":utf8");                        # 將fh的資料編碼置為utf-8

--------------------------2-----------------------------------

perl從5.6開始已經開始在內部使用utf8編碼來表示字元,也就是說對中文以及其他語言字元的處理應該是完全沒有問題的。我們只需要利用好encode這個模組便能充分發揮perl的utf8字元的優勢了。

下面就以中文文字的處理為例進行說明,比如有乙個字串"測試文字",我們想要把這個中文字串拆成單個字元,可以這樣寫:

use encode;

$dat="測試文字";

$str=decode("gb2312",$dat);

@chars=split //,$str;

foreach $char (@chars) ;

print "not gbk: $@\n" if $@;

eval ;

print "not utf8: $@\n" if $@;

eval ;

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函式傳遞了第三個引數, 要求有異常字元的時候報錯. 我們用eval捕獲錯誤, 轉碼失敗說明字串本來不是這種編碼. 另外注意我們每次都把$str拷貝到$str2, 這是因為decode第三個引數為1時, decode以後, 傳給它的字串引數(第二個引數會被清空). 我們拷貝一下, 這樣每次被清空的都是$str2, $str不變.

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

輸出字串在程式內被正確地處理後, 要展現給使用者. 這時我們需要把字串從perl internal form轉化成使用者能接受的形式. 簡單地說, 就是把字串從utf8編碼轉換成輸出的編碼或表現介面的編碼. 這時候, 我們使用$str = encode::encode(『charset』, $str);. 同樣可以分為幾種情況.

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

程式**:

wide character in print at unicode.pl line 10.

2) gui程式. 這個應該是不用幹什麼, utf8編碼, utf8 flag開啟就行. 沒有實際測試過.

3) 做http post. 看網頁表單要求什麼編碼. utf8 flag開或關無所謂, 因為http post傳送出去的只是字串中的資料部分, 不管utf8 flag.

perlio

perlio為我們的輸入/輸出轉碼提供了便利. 它可以針對某個檔案控制代碼, 輸入的時候自動幫你轉碼並開啟utf8 flag, 輸出的時候, 自動幫你轉碼並關閉utf8 flag. 假設你的終端locale是gb2312, 看下面的例子:

程式**:

use strict;

binmode(stdin, ":encoding(gb2312)");

binmode(stdout, ":encoding(gb2312)");

while (<>)

執行後輸入"中國", 結果:

程式**:

中國2

這樣我們就省去了輸入和輸出時轉碼的麻煩. perlio可以作用於任何檔案控制代碼, 具體請參考perldoc perlio.

相關api

都是encode模組的:

$octets = encode(encoding, $string [, check]) 把字串從utf8編碼轉成指定的編碼, 並關閉utf8 flag.

$string = decode(encoding, $octets [, check]) 把字串從其他編碼轉成utf8編碼, 並開啟utf8 flag, 不過有個例外就是, 如果字串是僅僅ascii編碼或ebcdic編碼的話, 不開啟utf8 flag.

is_utf8(string [, check]) 看看utf8 flag是否開啟. 如果第二個引數為真, 則同時檢查編碼是否符合utf8. 這個檢測不一定準確, 跟decode方式檢測效果一樣.

_utf8_on(string) 開啟字串的utf flag

_utf8_off(string) 關閉字串的utf flag

最後兩個是內部函式, 不推薦使用.

參考perldoc encode.

utf8和utf-8

前面我們提到的一直都是utf8. 在perl中, utf8和utf-8是不一樣的. utf-8是指國際上標準的utf-8定義, 而utf8是perl在國際標準上做了一些擴充套件, 能相容的內碼要比國際標準的多一些. perl internal form使用的是utf8. 另外順便提一下, 字符集的名稱是不區分大小寫的並且"_"和"-"是等價的.

ebcdic

ebcdic是一套遺留的寬字元解決方案, 不同於unicode, 它不是ascii的超集. 上面介紹的方案並不完全適用於ebcdic. 關於ebcdic, 請參考perldoc perlebcdic

python 字元編碼處理問題總結

一直以來,python中的中文編碼就是乙個大問題,為他他並不能智慧型識別編碼,而實際上其他語言也很難做到。str和unicode物件的轉換,通過encode和decode實現。當我們向網頁提交包含中文的表單資料時,常常會出現亂碼的錯誤,拿我這幾天對駕校網上打卡系統實踐舉例吧。可以看到 姓名 那欄提交...

下標處理問題

下標處理問題 主要是針對於插入排序演算法寫的程式,其他情況可以借鑑這些思路。數學上或者通常意義上,下標都是從1開始的,但是在多數程式語言裡面陣列下標都是從0開始的,這就很惱火了,簡單乙個下標處理起來卻異常麻煩!請看 例如 1 典型的陣列下標越界問題 假設有個陣列 a 0 a 1 我們要用插入法排序,...

ORACLE 異常處理問題處理

create or replace procedure pro people as begin select per id into v per id from people where id i id exception when no data found then v per id 1 whe...