我有一个生成UTF-8文件的应用程序,但是其中一些内容编码不正确。一些字符被编码为iso-8859-1 aka iso-latin-1或cp1252 aka Windows-1252。有没有一种方法可以恢复原始文本?

最佳答案

是的!

显然,最好修复程序来创建文件,但这并不总是可能的。以下是两个解决方案。

一行可以包含多种编码

Encoding::FixLatin提供了一个名为fix_latin的函数,该函数对包含UTF-8,iso-8859-1,cp1252和US-ASCII的混合文本进行解码。

$ perl -e'
   use Encoding::FixLatin qw( fix_latin );
   $bytes = "\xD0 \x92 \xD0\x92\n";
   $text = fix_latin($bytes);
   printf("U+%v04X\n", $text);
'
U+00D0.0020.2019.0020.0412.000A

虽然采用了启发式方法,但是它们相当可靠。仅以下情况将失败:
  • 使用iso-8859-1或cp1252进行编码的[ÁÁÅÆÅÆÇÈÉÊËÌËÌÐÒÓÔÕÖ×ØÙÚÛÜÝÞß]之一,然后是[€?使用iso-8859-1或cp1252编码的<NBSP>®°±²³³µ¶·¸¼º¼½¾¾¿]。
  • 一种使用iso-8859-1或cp1252编码的[àáããäåæçèéêëêëëëííííï]编码,然后是两个[€?ƒ„ ...†‡ˆ‰Š‹ŒŽ“”••---〜™š›œžŸ<SHY>¡¢£¤使用iso-8859-1或cp1252编码的¥ _________________ ________的<NBSP>®。
  • 使用iso-8859-1或cp1252编码的[ðñòóôõö÷]其中之一,然后是两个使用iso-8859-1或cp1252进行编码的¥¥§ª<SHY>®°±²³³µ¶·¸¼¼½¾¾¿]。

  • 使用核心模块Encode可以产生相同的结果,尽管我认为这比安装了Encoding::FixLatin::XS的Encoding::FixLatin慢很多。
    $ perl -e'
       use Encode qw( decode_utf8 encode_utf8 decode );
       $bytes = "\xD0 \x92 \xD0\x92\n";
       $text = decode_utf8($bytes, sub { encode_utf8(decode("cp1252", chr($_[0]))) });
       printf("U+%v04X\n", $text);
    '
    U+00D0.0020.2019.0020.0412.000A
    

    每行仅使用一种编码
    <NBSP>在字符级别上工作。如果知道每一行都是使用UTF-8,iso-8859-1,cp1252或US-ASCII中的一种完全编码的,则可以通过检查该行是否为有效的UTF-8来使过程更加可靠。
    $ perl -e'
       use Encode qw( decode );
       for $bytes ("\xD0 \x92 \xD0\x92\n", "\xD0\x92\n") {
          if (!eval {
             $text = decode("UTF-8", $bytes, Encode::FB_CROAK|Encode::LEAVE_SRC);
             1  # No exception
          }) {
             $text = decode("cp1252", $bytes);
          }
    
          printf("U+%v04X\n", $text);
       }
    '
    U+00D0.0020.2019.0020.00D0.2019.000A
    U+0412.000A
    

    虽然采用了启发式方法,但是它们非常可靠。仅当给定行的以下所有为真时,它们才会失败:
  • 该行使用iso-8859-1或cp1252进行编码,
  • 至少一个[?„„†‡ˆ‰Š‹ŒŽ“”•-〜™š›œžŸ<SHY>¡£¤¥¦§¨©ª«fix_latin®¯°±²³´该行中存在µ¶·¸º»¼½¾¿
  • 在所有[ÁÁÅ‚ÅÆÇÈÉÊËÌËÏÑÒÓÔÕÖ×ØÙÚÛÜÝÞß]实例中,都始终紧随[€?ƒ„ ...†‡ˆ‰ŠŒŽ“”••---™™ ©ª«¬<NBSP>®°±²³³µ¶·¸¹º»¼½¾¿],
  • 在[àáããåååççéééëëëëííïï]的所有实例中,总是紧跟着[€?ƒ„…†‡Š‰Š‹''Ž''“••---〜™š›œžŸ<SHY>中的两个。 «¬<NBSP>®Â±±²³´µ¶·¸¹º»¼½¾¿],
  • 在[ðñòóôõö÷]的所有实例中,总是紧跟着[],?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,? ¬oji oji code code¬²²²
  • 该行中没有[øùúûüýþÿ]出现,而
  • of€None oji oji oji oji oji oji oji oji oji oji oji oji oji oji oji oji oji oji oji oji oji oji除非前面提到,否则行中都存在··················


  • 笔记:
  • Encoding::FixLatin安装命令行工具<SHY>来转换文件,使用第二种方法编写一个很简单。
  • <NBSP>(函数和文件)都可以通过安装Encoding::FixLatin::XS来加快。
  • 可以将相同的方法用于UTF-8与其他单字节编码的混合。可靠性应该相似,但是可以有所不同。
  • 09-30 12:29