我该如何在Perl中检查UTF-16文件名是否存在?

5
我有一个以UTF-16编码的文本文件,每一行包含由制表符分隔的多个列。对于那些关心的人来说,该文件是iTunes的播放列表TXT导出。第27列包含文件名。
我正在Linux中使用Perl 5.8.8读取它,类似于以下代码:
binmode STDIN, ":encoding(UTF-16)";
while(<>)
{
    chomp;
    my @cols = split /\t/, $_;
    my $filename = $cols[26];   # Column #27 contains the filename
    print "File exists!" if (-e "$filename");
}

请注意:我已经缩短了这段代码片段。在我的实际代码中,我进行了一些替换,将iTunes使用的绝对Windows文件名转换为在我的Linux框中有效的文件名。
尽管文件存在,但(-e)文件测试未返回true。我认为这与字符串是UTF-16有关,但无法找出问题所在。实际的文件名仅使用ASCII字符。如果打印$filename变量,则文件名会正确打印。
Perl中的文件名可以是UTF16吗?有什么想法可以使这个代码片段工作吗?

1
在我花费任何时间之前,my $filename =~ $cols[26]; 是什么意思? - Sinan Ünür
抱歉 - 是一个打字错误。应该是StackOverflow上的错别字,而不是我的原始代码。问题仍然存在。 - blt04
文件名不能原生地使用UTF-16,因为UTF-16充满了零字节。现在许多Linux发行版都使用UTF-8,所以这将是第一个尝试的编码方式。 - bobince
3个回答

5
UTF-16文本通过:encoding层进行处理。当它进入$_时,无法确定它曾经是UTF-16。我认为这不是你的问题。
我猜你的文件名中可能有一些空格(当你尝试打印它时没有注意到),或者你所在的目录并非你认为的那个目录。
试试:
if (-e $filename) { print "File exists!" } 
else { print "File <$filename> not found" }

仔细检查文件名。您还可以使用Cwd;并打印出当前目录。


感谢cjm:在我发布我的解决方案后,我看到了这个,但你是正确的。 - blt04

4
我找到了解决方案:
第27列是最后一列,文件采用0d0a(\r\n)行尾符进行编码。chomp只能删除0a(\n),我不确定为什么之前没有发现这一点,但它与UTF16无关。
添加以下内容:
s/\r$//;

经过chomp处理,问题得以解决。

非常感谢你的帮助,很抱歉让你走了一条兔子洞。


你也可以尝试使用:crlf:encoding(UTF-16),不过我从未尝试过在UTF-16中使用:crlf,所以我不确定是否有效。我只在单字节编码中使用过:crlf。 - cjm

2
如果像你所说的那样,实际文件名只使用ASCII字符,那么...
$filename =~ s/\0//g;

工作?无论如何,xxd应该有助于下次遇到类似情况时。

[sinan@archardy ~]$ xxd /mnt/c/Documents\ and\ Settings/sinan/Desktop/test.txt
0000000: fffe 2f00 6800 6f00 6d00 6500 2f00 7300  ../.h.o.m.e./.s.
0000010: 6900 6e00 6100 6e00 2f00 7400 6500 7300  i.n.a.n./.t.e.s.
0000020: 7400 6d00 6500 2e00 7400 7800 7400 0d00  t.m.e...t.x.t...
0000030: 0a00                                     ..

我看到你已经在我创建测试文件并重新启动Linux的时间内解决了你的问题。哦,好吧。


你可能会认为它会起作用,但实际上并没有。-e 仍然返回 false。为了测试我的代码的其余部分,我尝试在 Perl 文件中硬编码一个文件名,并且它可以工作。即使使用您的空值替换建议从 iTunes UTF16 文件中读取也不起作用。 - blt04
在进行空值替换之前,请尝试使用utf8:downgrade($filename)。 - Inshallah
好的,让我们来调试一下,看看$filename里面实际上是什么,逐字节地。 - bobince
再次感谢Sinan。当我通过xxd更仔细地查看时,最终看到了0d0a。 - blt04

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