我有一个用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吗?有关如何使此代码段生效的任何想法吗?
答案 0 :(得分:5)
UTF-16文本由:encoding层处理。当它进入$_
时,没有办法告诉它曾经是UTF-16。我认为这不是你的问题。
我的猜测是你的文件名中有一些空格(当你尝试将其打印出来时没有注意到)或者你不在你认为的目录中。
尝试
if (-e $filename) { print "File exists!" }
else { print "File <$filename> not found" }
并仔细检查文件名。您也可以use Cwd;
打印出当前目录。
答案 1 :(得分:3)
我找到了解决方案:
第27列是最后一列,文件使用0d0a(\ r \ n)行结尾进行编码。 chomp只删除了0a(\ n)。不知道为什么我之前没有看到这个,但它与UTF16没有任何关系。
添加:
s/\r$//;
在chomp修复问题之后。
感谢您的帮助 - 抱歉让您沿着兔子路走下去。
答案 2 :(得分: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时花了很长时间才解决了问题。哦,好吧。