使用CSV文件复制/重命名UTF8名称的图像

5
我正在编写一个脚本,根据csv文件批量重命名和复制图像。csv文件包括第一列:旧名称和第二列:新名称。我想将csv文件用作perl脚本的输入,以便它检查旧名称并使用新名称将其复制到一个新文件夹中。我遇到的问题(我认为)与图像有关。它们包含像ß这样的utf8字符。当我运行脚本时,它打印出Barfu├ƒg├ñsschen,而应该是Barfußgässchen,还会出现以下错误:
Unsuccessful stat on filename containing newline at C:/Perl64/lib/File/Copy.pm line 148, <$INFILE> line 1.
Copy failed: No such file or directory at X:\Script directory\correction.pl line 26, <$INFILE> line 1.

我知道这与Binmode utf8有关,但即使我尝试一个简单的脚本(在这里看到它:How can I output UTF-8 from Perl?):

use strict;
use utf8;
my $str = 'Çirçös';
binmode(STDOUT, ":utf8");
print "$str\n";

它输出的是这个:Ãirþ÷s

这是我的整个脚本,有人能解释一下我错在哪里吗?(因为我在测试东西,所以代码不是很干净)。

use strict;
use warnings;
use File::Copy;
use utf8;

my $inputfile  = shift || die "give input!\n";
#my $outputfile = shift || die "Give output!\n";

open my $INFILE,  '<', $inputfile   or die "In use / not found :$!\n";
#open my $OUTFILE, '>', $outputfile  or die "In use / not found :$!\n";

binmode($INFILE, ":encoding(utf8)");

#binmode($OUTFILE, ":encoding(utf8)");

while (<$INFILE>) {
s/"//g;
my @elements = split /;/, $_;

my $old = $elements[1];
my $new = "new/$elements[3]";
binmode STDOUT, ':utf8';
print "$old | $new\n";

copy("$old","$new") or die "Copy failed: $!";
#copy("Copy.pm",\*STDOUT);

#   my $output_line = join(";", @elements);
#    print $OUTFILE $output_line;
#print "\n"
}

close $INFILE;
#close $OUTFILE;

exit 0;

关于你的第一个片段:.pl文件本身是否以utf8编码?use utf8编译指示告诉Perl你的源代码是用utf8编写的,它不涉及数据。 - simbabque
你将输出打印到哪里?Linux shell中吗?另外,你是如何创建文件的? - Alastair McCormack
我可以确认,在我的Linux shell上,使用LANG设置为en_GB.UTF-8和Putty设置为UTF-8时,您的第一个代码片段可以正常工作。我是在同一个shell中使用VIM创建该文件的。 - Alastair McCormack
@Fuzzyfelt 如果你的意思是我在Windows系统上,那么是的。我手动创建了CSV文件。在目录上执行了dir命令并在Excel中打开了它。我还在同一文件中创建了新名称。 - Jan
1个回答

3

您需要确保流程的每个步骤都使用UTF-8。

创建输入CSV时,您需要确保以UTF-8格式保存,最好不带BOM。Windows记事本会添加BOM,因此请尝试使用Notepad++,它可以更好地控制编码。

您还有一个问题,即Windows控制台默认不符合UTF-8标准。请参见Unicode characters in Windows command line - how?。要么使用chcp 65001设置代码页,要么不要更改STDOUT编码。

在您的代码方面,关于换行符的第一个错误可能是由于CSV中的尾随换行符引起的。请在while (<$INFILE>) {之后添加chomp()

更新:

要"处理"文件,您需要使用正确的语言环境对文件名进行编码-请参见如何使用Perl在Windows中创建Unicode文件名使用Unicode文件名的通用文件I/O API方法是什么?。假设您正在使用西方1252 / Latin,则意味着当您的复制命令将如下所示:
copy(encode("cp1252", $old), encode("cp1252", $new))

此外,您的打开操作还应对文件名进行编码:
open my $INFILE,  '<', encode("cp1252", $inputfile)

更新 2:
由于你在 DOS 窗口中运行,因此请删除 binmode(STDOUT, ":utf8"); 并保留默认的代码页。

我在notepad++中创建了CSV文件,使用utf8编码且没有BOM,所以这不应该是问题所在。我正在检查您给我的另外两个建议。 - Jan
while (<$INFILE>) { 后面添加 chomp; 解决了第一个错误。先设置代码页,然后再尝试运行脚本并没有改变任何东西。我仍然收到复制失败的消息。我打印出旧名称和新名称,你可以看到旧名称是不正确的,这就是为什么它与实际文件不匹配并且失败的原因。 - Jan

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