2014-07-08 45 views
0

因此,我有一個迭代器對象返回行,稍後解碼爲迭代器不知道編碼。一切都好,直到我試圖添加UTF-16支持。從基於行的迭代器解碼帶有CRLF行結尾的UTF-16

這裏是我的粗略代碼:

use Encode qw(decode); 
my @lines; 
my $buffer = ''; 
while($buffer .= $iter->next){ 
    push @lines, decode("UTF-16LE", $buffer, Encode::FB_QUIET); 
} 

的數據是小端的UTF-16 CRLF行結束。以下是通過od -a泵送的第一行:

0000000 ff fe e nul m nul a nul i nul l nul ht nul l nul 
0000020 a nul n nul g nul u nul a nul g nul e nul ht nul 
0000040 e nul x nul a nul m nul p nul l nul e nul _ nul 
0000060 t nul e nul x nul t nul cr nul nl nul 

,我已經得到的問題是,我最終的結局分割線。第一行以CR結束,第二行以LF開頭,依此類推。

任何想法這裏發生了什麼,以及如何解決它?

編輯:

在仔細檢查,發生了什麼是基於行的迭代器返回的一切行動和包括LF,但(重要)NOT後的空字節。 decode()設置爲僅讀取緩衝區中的字符,因此下一次將唯一的LF保留在緩衝區中。下一次迭代出現並將所有內容添加到包含null的下一個LF。所以你最終會在一行結尾處出現一個CR,並在下一行結尾處出現LF。

我真的不知道該怎麼辦,除了已經在上面,上面寫着從decode()的輸出只有完整的生產線另一個緩衝區..

有什麼建議?

回答

3

這是當您嘗試使用期望ASCII的代碼讀取UTF-16時發生的情況。使用與ISO 8859-1和UTF-8等ASCII兼容的編碼,您可以用期望純ASCII的代碼(只要8位乾淨)讀取它們,然後稍後對它們進行解碼。這只是不適用於UTF-16。 UTF-16LE更糟糕,因爲LF代表的是0A00,但類似的問題也會隨着big-endian而出現。

當您的文件包含U+010A時會發生什麼?或U+020A?或者U+0A01?或...

你將不得不教你的迭代器關於編碼,或者在迭代器下面插入一層來做解碼,或者寫一個迭代器,它從另一個迭代器中讀取「行」並將它們組裝成正確解碼實際線路。

+0

Yep ,謝謝,迅速得出這個結論!我認爲真正應該發生的是這些迭代器應該處理塊而不是行,直到內容被解碼。如果需要的話,我們可以將它轉換成線。具有這些意義的好處將能夠正確支持二進制數據,而不是意外地...... – Dan

2

看起來好像您正在使用Iterator::File?我建議你放棄它,正是因爲這樣的問題,因爲它不提供任何超出標準界面的東西。

open my $fh, '<:encoding(UTF-16LE)', 'myfile.txt' or die $!; 

打開你的文件,然後用

my @lines; 
while (my $buffer = <$fh>) { 
    push @lines, $buffer; 
} 

或只是

my @lines = <$fh>; 

讀它,但你有沒有考慮處理的文件中的行由行?你很少需要同時在內存中存儲所有的數據。

+0

不確定我同意你的第一段。我的理解是'FB_QUIET'消耗緩衝區的成功解碼部分。其他:+1 – tjd

+0

@tjd:謝謝。我不知道如何工作。固定。 – Borodin

+0

是的,通常我會使用一個文件句柄,但是這是綁定到一個系統,可以從各個位置獲取文件並將它們呈現爲迭代器。迭代器返回行,但不知道編碼。我希望能夠使用UTF16文件。將內容讀入數組僅僅是一個例子(實際上,這個東西本身就是一個迭代器,它解碼CSV並返回hashrefs,但這是無關緊要的:)) – Dan