2015-05-30 43 views
4

我有一個CSV文件,說win.csv,其文本編碼在windows-1252。首先,我使用iconv使它成爲utf8。如何從Text :: CSV utf8輸出?

$iconv -o test.csv -f windows-1252 -t utf-8 win.csv 

然後我讀出的變換CSV具有以下Perl腳本(utfcsv.pl)文件。

#!/usr/bin/perl 
use utf8; 
use Text::CSV; 
use Encode::Detect::Detector; 

my $csv = Text::CSV->new({ binary => 1, sep_char => ';',}); 
open my $fh, "<encoding(utf8)", "test.csv"; 

while (my $row = $csv->getline($fh)) { 
    my $line = join " ", @$row; 
    my $enc = Encode::Detect::Detector::detect($line); 
    print "($enc) $line\n"; 
} 

$csv->eof || $csv->error_diag(); 
close $fh; 
$csv->eol("\r\n"); 
exit; 

然後輸出如下。

(UFT-8) ......... 
() ..... 

即所有行的編碼都被檢測爲UTF-8(或ASCII)。但實際輸出似乎不是UTF-8。事實上,如果我節省然後output.txt的的編碼被檢測爲窗口1252文件

$./utfcsv.pl > output.txt 

的輸出。

問題:如何獲得UFT-8中的輸出文本?

注:

  1. 環境:openSUSE的13.2 x86_64的,Perl 5.20.1
  2. 我不使用文字:: CSV ::編碼,因爲安裝失敗。 (因爲test.csv是以UTF-8轉換的,所以使用Text :: CSV :: Encoded很奇怪。)
  3. 我使用以下腳本來檢查編碼。 (我也用它來找出初始CSV文件win.csv的編碼。)

#!/usr/bin/perl 
use Encode::Detect::Detector; 
open my $in, "<","$ARGV[0]" || die "open failed"; 
while (my $line = <$in>) { 
    my $enc = Encode::Detect::Detector::detect($line); 
    chomp $enc; 
    if ($enc) { 
    print "$enc\n"; 
    } 
} 
+0

您的文本是否包含ASCII以外的任何字符?是的,確定真正的編碼應該沒有問題。否則,編碼檢測器給出任意結果。 –

+0

是的。我正在處理一個包含很多ü的德文文本。 –

+0

嘗試從http://stackoverflow.com/questions/627661/how-can-i-output-utf-8-from-perl的最佳答案 - 我很確定這會爲您解決這個問題! – Gaurav

回答

10

您已設置輸入文件句柄的編碼(其中,順便說一下,應該是<:encoding(utf8) - 注意冒號)但是你有沒有指定輸出通道的編碼,這樣的Perl將未編碼的字符值發送到輸出

適合單個字節的字符的Unicode值 - 位於0和0x7F之間的基本拉丁文(ASCII)以及位於0x80和0xFF之間的Latin-1 Supplement - 非常相似到Windows代碼頁1252.特別是在Unicode和CP1252中,帶有過濾功能的小寫字母是0xFC,因此如果輸出未經編碼,文本將看起來像CP1252,instea d的兩個字節的序列0xC3 0xBC這是用UTF-8編碼的相同編碼點

如果在STDOUT上使用binmode來設置編碼,那麼數據將被正確輸出,但使用open編譯指示最簡​​單像這樣

use open qw/ :std :encoding(utf-8) /; 

它將爲STDIN,STDOUT和STDERR以及任何新打開的文件句柄設置編碼。這意味着在打開CSV文件時不必指定它,並且代碼將如下所示

請注意,我還添加了use strictuse warnings,這在任何Perl程序中都是必不可少的。我也有 使用autodie刪除所有IO操作的狀態檢查的需要,並且我已經利用Perl在雙引號內部插入數組的方式,在元素之間放置一個空格以避免需要join調用

#!/usr/bin/perl 

use utf8; 
use strict; 
use warnings 'all'; 
use open qw/ :std :encoding(utf-8) /; 
use autodie; 

use Text::CSV; 

my $csv = Text::CSV->new({ binary => 1, sep_char => ';' }); 

open my $fh, '<', 'test.csv'; 

while (my $row = $csv->getline($fh)) { 
    print "@$row\n"; 
} 

close $fh; 
+0

謝謝您的詳細解答。我瞭解情況。 –