Perl - 将PC UTF-8转换为PC ANSI

4

我有一个使用PC UTF-8编码的文件,想要将其转换为PC ANSI格式。

我尝试了下面的方法,但输出文件总是PC UTF-8格式。

use Encode;

$infile = $ARGV[0];
open(INFILE, $infile);

my $outfile = "temp.txt";

open(OUTFILE, ">$outfile");

while(<INFILE>) {
  my $row = $_;
  chomp $row;

  $row = Encode::encode("Windows-1252", $row);
  print OUTFILE $row."\n";

}

close INFILE;
close OUTFILE;

2
将行使用 chomp 函数去除换行符再添加 \n 稍显浪费。 - Keith Thompson
1
你能否尝试使用一个非常小的文件,比如只有一个短行和一个单个的非ASCII字符,并展示输入和输出的十六进制转储吗? - Keith Thompson
1
这与您的问题无关,但是open的三参数版本更受推荐。http://modernperlbooks.com/mt/2010/04/three-arg-open-migrating-to-modern-perl.html - Keith Thompson
2个回答

10
问题在于您从未解码您编码的数据。
use strict;
use warnings;
use Encode qw( encode decode );

open(my $INFILE,  '<', $ARGV[0]) or die $!;
open(my $OUTFILE, '>', $ARGV[1]) or die $!;

while (my $utf8 = <$INFILE>) {
   my $code_points = decode('UTF-8', $utf8);    # <-- This was missing.
   my $cp1252 = encode('cp1252', $code_points);
   print $OUTFILE $cp1252;
}

但是你可以更容易地完成这个任务:
use strict;
use warnings;

open(my $INFILE,  '<:encoding(UTF-8)',  $ARGV[0]) or die $!;
open(my $OUTFILE, '>:encoding(cp1252)', $ARGV[1]) or die $!;

while (<$INFILE>) {
   print $OUTFILE $_;
}

1
(cp1252只是写作Windows-1252的简便方式) - ikegami
1
这似乎是有效的。我只是收到了一个消息,上面写着""\x{feff}"不映射到cp1252"。有没有什么好的方法可以过滤掉这些? - user333746
1
如果这是唯一的问题字符,您可以安全地使用s/^\x{FEFF}//;(解码后)将其删除。这是BOM - ikegami
转码和替换一些内容并不是什么罕见的情况,例如如果您正在处理一些包含元数据编码的文件,比如HTML。 - Wolf

1

不要手动进行解码和编码,应该使用PerlIO-Layers。您可以使用binmode函数指定层,或在三个参数的open中的模式参数中指定:

use strict; use warnings;
use autodie;

open my $INFILE,  '<:utf8',                 $ARGV[0];
open my $OUTFILE, '>:encoding(iso-8859-1)', "temp.txt";
#                   ^-- the layers

while (my $line = <$INFILE>) {
  print $OUTFILE $line;
}

请注意,默认情况下Perl不会以UTF8格式打开文件,您还需要指定解码层。编码层:encoding(utf8)非常常见,您可以直接使用:utf8
您可以使用以下命令列出所有可用的编码格式:
use Encode;
print "$_\n" for Encode->encodings();

@user333746 ① 检查可用编码列表,以查看当前已安装的内容。② 请将您的代码与我的更新帖子进行比较;该层是 :encoding(foo-bar)(我的初始帖子有一个错误)。③ 您正在运行什么版本的Perl?为什么要使用 eval - 您是否在 mod_perl 下? - amon
1
你为什么从Windows-1252改成iso-8859-1?它们不一样,而且OP明确表示他想要“ANSI”编码(这是Windows称其单字节本地编码的方式,大多数机器上是Windows-1252,也叫cp1252,而不是iso-8859-1)。 - ikegami

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接