我有一个生成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
虽然采用了启发式方法,但是它们相当可靠。仅以下情况将失败:
<NBSP>
®°±²³³µ¶·¸¼º¼½¾¾¿]。 <SHY>
¡¢£¤使用iso-8859-1或cp1252编码的¥ _________________ ________的<NBSP>
®。 <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
虽然采用了启发式方法,但是它们非常可靠。仅当给定行的以下所有为真时,它们才会失败:
<SHY>
¡£¤¥¦§¨©ª«fix_latin
®¯°±²³´该行中存在µ¶·¸º»¼½¾¿<NBSP>
®°±²³³µ¶·¸¹º»¼½¾¿],<SHY>
中的两个。 «¬<NBSP>
®Â±±²³´µ¶·¸¹º»¼½¾¿],笔记:
<SHY>
来转换文件,使用第二种方法编写一个很简单。 <NBSP>
(函数和文件)都可以通过安装Encoding::FixLatin::XS来加快。