Strawberry perl 在写入 UTF-8 文件时给了我一个 "Wide character in print"

Strawberry perl gives me a "Wide character in print" when writing to a UTF-8 file

我是 运行 Strawberry perl 脚本,它读取文件并进行一些处理并将输出写入另一个文件。当它似乎在原始文件中遇到一些非 ASCII 字符(扩展)时,我有时会收到此消息。

Wide character in print at cv2pf.pl line 348, <$fh> chunk 1307

这意味着什么,我该如何解决?它似乎对输出文件没有任何影响,除非我遗漏了什么。

这里给出的解决方案: 不能解决问题。我正在将输出写入文件而不是控制台,因此该解决方案不起作用。

我在打开文件时指定了 UTF-8,但它仍然给出错误

# Detect the file type UTF-8 or not
if (!open(READ,$sourcefile))
{
    print "Error: Could not open $sourcefile for detecting.\n";
    next;
}
my $line = <READ>;
my $enc = Encode::Detect::Detector::detect($line);
print "File encoding: $enc\n";
close READ;

if ($enc eq "UTF-8")
{
    if (!open(READ,'<:encoding(UTF-8)',$sourcefile))
    {
        print "Error: Could not open UTF-8 $sourcefile for reading.\n";
        next;
    }
}
else
{
    if (!open(READ,$sourcefile))
    {
        print "Error: Could not open $sourcefile for reading.\n";
        next;
    }
}

if (!open($fh,"+>:encoding(utf8)","$base.m.csv"))
{
    print "Error: Could not open $base.m.csv for reading/writing.\n";
    next;
}

undef $/;
$_=<READ>;
# remove the BOM
if ($enc eq "UTF-8")
{
    $_ =~ s/\x{FEFF}//g;
}
# convert unix line ending to dos
$_ =~ s/\r?\n|\r/\r\n/g;
print $fh $_;
close READ;

$/ = "\r\n";
seek ($fh,0,0);

my $csv = Text::CSV->new ( { allow_whitespace => 1, binary => 1 } );  # should set binary attribute.

在输出中我看到源文件是 UTF-8 并且相应地作为 UTF-8 文件打开。

File encoding: UTF-8

我在这里错过了什么?

其他要求的代码:

第 348 行

print {$handles{$currency}} "P" . $row->{'Name'} . "\r\n";

my %handles;
curcheck: while ( $row = $csv->getline_hr( $fh ) ) {
    my $currency=$row->{'Currency'};
    if (exists $handles{$currency}) {
        next curcheck;
    }
    $handles{$currency}=return_fh();
    if (!open($handles{$currency},">:encoding(utf8)","$base-$currency.out"))
    {
        print "Error: Could not open $base-$currency.out for writing.\n";
        next file;
    }

    binmode($handles{$currency})
}
seek ($fh,0,0);
$row = $csv->getline ($fh);


...

sub return_fh {
    local *FH;
    return *FH;
}

经过大量挖掘后发现错误是因为您使用 :encoding(utf8) 的显式模式显式打开文件句柄的哈希,然后立即将其更改为 unencoded 使用 binmode

以下内容对于任何 Perl 程序也非常重要

  • use strictuse warnings 'all'

  • 开始你的代码
  • 声明所有变量尽可能接近它们的第一个使用点;通常在定义时

  • 使用 词法文件句柄 而不是全局句柄。例如

    unless ( open my $read, '<:encoding(UTF-8)', $sourcefile ) {
        print "Error: Could not open UTF-8 $sourcefile for reading.\n";
        next;
    }
    

    它们作为子例程参数传递起来要简单得多。当它们超出范围时,Perl 将自动关闭

  • 使用 $var = undef 而不是 undef $var 将变量设置为 undef。并使用 local $/ 临时对全局变量执行此操作,并使用代码块 { ... } 来限制更改范围

解决方案是 use open 使用适当的编码层。您正在写入文件而不是 STDOUT 的事实不会改变任何东西。

# Add encoding layer to STD*
use Win32 qw( );
use open ':std', ':encoding(cp'.Win32::GetConsoleOutputCP().')';

# Set default encoding layer for files open in scope of this.
use open ':encoding(UTF-8)';

open(my $fh, '>', $qfn)
   or die("Can't create \"$qfn\": $!\n");