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 吗?任何想法如何让这个代码片段工作?

4

3 回答 3

5

UTF-16 文本由 :encoding 层处理。当它进入. 时$_,无法判断它曾经是 UTF-16。我不认为这是你的问题。

我的猜测是您的文件名中有一些空格(当您尝试打印它时没有注意到)或者您不在您认为的目录中。

尝试

if (-e $filename) { print "File exists!" } 
else { print "File <$filename> not found" }

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

于 2009-08-22T20:47:30.723 回答
4

我想出了解决方案:

第 27 列是最后一列,文件以 0d0a (\r\n) 行结尾编码。chomp 只删除了 0a (\n)。不知道为什么我以前没有看到这个,但它与 UTF16 没有任何关系。

添加:

s/\r$//;

在 chomp 解决问题之后。

感谢您的帮助 - 很抱歉让您走上兔子之路。

于 2009-08-22T20:52:49.403 回答
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 ../.home/.s.
0000010: 6900 6e00 6100 6e00 2f00 7400 6500 7300 inan/.tes
0000020: 7400 6d00 6500 2e00 7400 7800 7400 0d00 tme..txt..
0000030: 0a00 ..

我看到您在我创建测试文件并重新启动到 Linux 的过程中解决了您的问题。那好吧。

于 2009-08-22T20:17:06.917 回答