如果文件被写为小端或大端,如何检入perl?

时间:2016-12-15 20:49:40

标签: perl encoding endianness utf-16le

实际上我必须解析一些可以是任何形式的endian(Big或Little)的文件。如果我使用一个编码并解析其他编码,Perl解释器就会死掉。

open (my $fh, "<:raw:encoding(UTF-16LE):crlf", $ARGV[0]) or die cannot open file for reading : $! \n";

open (my $fh, "<:raw:encoding(UTF-16BE):crlf", $ARGV[0]) or die cannot open file for reading : $! \n";

输出(对于LE中的文件和perl的编码为BE)

UTF-16BE:Malformed HI surrogate dc00 at toASCII.pl line 123.

2 个答案:

答案 0 :(得分:5)

大多数UTF-16le文件都是有效的UTF-16be文件,反之亦然。例如,无法判断0A 00是否表示U + 000A(UTF-16le)或U + 0A00(UTF-16be)。所以,假设没有BOM,你必须猜测。

可能的启发式(按可靠性的降序排列):

  1. U + FFFE不是角色(保证)。
    • 如果文件以FF FE开头,则必须为UTF-16le。
    • 如果文件以FE FF开头,则必须为UTF-16be。
    • 如果文件无效UTF-16be,则必须为UTF-16le。
    • 如果文件无效UTF-16le,则必须为UTF-16be。
    • 如果使用UTF-16be解码时文件包含非字符,则必须为UTF-16le。
    • 如果使用UTF-16le解码时文件包含非字符,则必须为UTF-16be。
  2. U + 0A00当前未分配,但U + 000A(LINE FEED)非常常见。
    目前未分配U + 0D00,但U + 000D(CARRIAGE RETURN)非常常见。
    • 如果文件包含0A 000D 00,那么它可能是UTF-16le。
    • 如果文件包含00 0A00 0D,那么它可能是UTF-16be。
    • 如果文件在使用UTF-16be解码时包含未分配的字符,那么它可能是UTF-16le。
    • 如果文件在使用UTF-16le解码时包含未分配的字符,那么它可能是UTF-16be。
  3. 基于文件格式知识的启发式算法。 (Example
  4. 文件可能包含的字符数多于字符数U + xx00
    • 如果该文件包含许多xx 00且很少00 xx,那么它可能是UTF-16le。
    • 如果该文件包含许多00 xx且很少xx 00,那么它可能是UTF-16be。
  5. 注意:

    • #4和#5说“它可能”而不是“它必须”,因为今天未分配的内容明天可以分配。
    • #3包括#1,但#1是便宜的测试。
    • #5包括#4,但#4几乎和#5一样可靠,没有保留一长串未经指定的字符随时间变化。

    您可以使用:raw在文件中啜饮,对其执行部分或全部上述测试以确定编码,然后使用decodes/\r\n/\n/g

答案 1 :(得分:1)

您不显示任何代码,但一般情况下,除非您知道应该从文件中读取哪些值,否则无法确定文件的字节顺序。例如,许多文件格式在开头保留几个字节以指示格式是什么,如果这适用于您正在处理的数据,那么您只需read这些字节,并且如果更改打开模式,则你没有得到你期待的东西

或者,由于如果选择了错误的格式,程序将会死亡,那么您可以使用它来测试所选格式是否正确。这样的事情应该适合

my $file = $ARGV[0];

open my $fh, '<:raw:encoding(UTF-16LE):crlf', $file or die $!;

eval { do_stuff_that_may_crash() };

if ( $@ ) {
    if ( $@ =~ /Malformed HI surrogate/ ) {
        open my $fh, '<:raw:encoding(UTF-16BE):crlf', $file or die $!;
        do_stuff_that_may_crash();
    }
    else {
        die $@;
    }
}

但是因为听起来do_stuff_that_may_crash()几乎就是你的所有程序,你应该找到一个更好的标准