如何从Text :: CSV utf8输出?

H. *_*doh 4 csv perl encoding utf-8

我有一个CSV文件,比如win.csv,其文本在windows-1252中编码.首先我使用iconv在utf8中制作它.

$iconv -o test.csv -f windows-1252 -t utf-8 win.csv
Run Code Online (Sandbox Code Playgroud)

然后我用以下Perl脚本(utfcsv.pl)读取转换后的CSV文件.

#!/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;
Run Code Online (Sandbox Code Playgroud)

然后输出如下.

(UFT-8) .........
() .....
Run Code Online (Sandbox Code Playgroud)

即,所有行的编码都被检测为UTF-8(或ASCII).但实际输出似乎不是UTF-8.实际上,如果我将输出保存在文件中

$./utfcsv.pl > output.txt
Run Code Online (Sandbox Code Playgroud)

然后将output.txt的编码检测为windows-1252.

问题:如何在UFT-8中获取输出文本?

笔记:

  1. 环境:openSUSE 13.2 x86_64,perl 5.20.1
  2. 我不使用Text :: CSV :: Encoded,因为安装失败.(因为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";
  }
}
Run Code Online (Sandbox Code Playgroud)

Bor*_*din 13

你已经设置了输入文件句柄的编码(顺便说一下,应该<:encoding(utf8)注意冒号),但你没有指定输出通道的编码,所以Perl会将未编码的字符值发送到输出

适合单个字节的字符的Unicode值 - 介于0和0x7F之间的基本拉丁语(ASCII),以及0x80和0xFF之间的Latin-1补充 - 非常类似于Windows代码页1252.特别是一个小写字母u diaresis在Unicode和CP1252中都是0xFC,因此如果输出未编码,文本将看起来像CP1252,而不是两个字节的序列0xC3 0xBC,这是UTF-8编码的相同代码点

如果您使用binmodeSTDOUT设置编码,那么数据将正确输出,但最简单的方法是使用这样的open编译指示

use open qw/ :std :encoding(utf-8) /;
Run Code Online (Sandbox Code Playgroud)

它将设置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;
Run Code Online (Sandbox Code Playgroud)