2012-02-25 26 views
0

我需要使用perl進行流處理使用UTF-16編碼的1Gb文本文件帶有unix風格結尾的小尾數(即,0x000A只有沒有0x000D在流中)和LE BOM。文件在Windows上處理(還需要Unix解決方案)。通過流處理,我的意思是使用while(<>),逐行讀寫。 會很高興有一個像下面這樣的命令行:
perl -pe「BEGIN {SOME_PREPARATION}; s/SRC/DST/g;」 infile.txt> outfile.txt在Windows中使用BOM和Unix行結束流處理UTF-16文件

用於測試輸入的十六進制轉儲(兩行: 「a」 和 「b」 的字母上的每個): FF FE 61 00 0A 00 62 00 0A 00

處理等S/b/C/G應該給一個輸出端( 「b」 與 「C」 代替): FF FE 61 00 0A 00 63 00 0A 00

PS。現在,在我所有的試驗中,或者CRLF輸出存在問題(0D 0A字節是輸出產生不正確的Unicode符號,並且我只需要0A00而沒有0D00來保持相同的unix樣式),或者每個新線路開關LE/BE,即相同的「a 「在一條線上是奇數線上6100和輸出中偶數線上的0061。

+0

Perl 5.what?有一些差異,我想確保我的答案適合你。 – ikegami 2012-02-25 20:38:36

+0

這很棘手的原因是,Perl添加了:crlf,然後纔有機會添加:編碼(UTF-16le)到句柄,並將它們放入錯誤的順序。 – ikegami 2012-02-25 20:39:49

+0

@ikegami你能解釋一下:crlf的用法?如果以「:crlf:encoding(UTF-16LE)」的形式出現,它會產生什麼? – 2012-02-26 00:49:17

回答

3

我想出的最好的是這樣的:

perl -pe "BEGIN { binmode $_, ':raw:encoding(UTF-16LE)' for *STDIN, *STDOUT }; s/b/c/g;" <infile.txt >outfile.txt 

但是請注意,我不得不使用<infile.txt而不是infile.txt,使文件將是對STDIN。理論上,open附註應控制魔術ARGV文件句柄所使用的編碼,但在這種情況下,我無法使其正確工作。

<infile.txtinfile.txt之間的區別在於打開文件的方式和時間。通過<infile.txt,文件連接到標準輸入,並在Perl開始運行之前打開。當您在BEGIN塊中使用binmode STDIN時,該文件已經打開,您可以更改編碼。

當您使用infile.txt時,文件名作爲命令行參數傳遞並放入@ARGV數組中。執行BEGIN塊時,該文件尚未打開,因此您無法設置其編碼。從理論上講,你應該能夠說:

use open qw(:std IO :raw:encoding(UTF-16LE)); 

,並有神奇的<ARGV>處理應用正確的編碼。但是在這種情況下,我一直無法做到這一點。

+0

哇!很棒! :)謝謝@cjm。正如我現在發現的那樣,我的代碼中存在的主要問題是在infile.txt之前沒有「<」。你能解釋爲什麼它是必要的,它有什麼不同?如果不是STDIN,那麼文件重定向沒有「<」? '因爲perl -pe「print」file.txt的效果很好,就好像file.txt在腳本里面的STDIN一樣...... BTW,腳本中使用UTF-16LE和UTF-16有什麼區別? – 2012-02-26 00:46:30

+0

爲什麼':raw'?另外,我總是用':utf8'和魔法'ARGV'來使用open。 – tchrist 2012-02-26 01:47:29

+0

@tchrist,我使用':raw'是因爲他在Windows上,默認情況下Perl會添加':crlf',但他希望使用Unix行結束符輸出。我不知道刪除':crlf'的更好方法。 – cjm 2012-02-26 02:15:22