0

我有一个大小合理的文本文档平面文件数据库,大部分以 8859 格式保存,这些文本文档是通过 Web 表单(使用 Perl 脚本)收集的。直到最近,我还在用一组简单的正则表达式协商常见的 1252 个字符(弯引号、撇号等):

$line=~s/\x91/\&\#8216\;/g; # smart apostrophe left
$line=~s/\x92/\&\#8217\;/g; # smart apostrophe right

... ETC。

然而,由于我决定我应该使用 Unicode,并且已经将我的所有脚本转换为读取和输出 utf8(这对所有新材料都有效),这些(现有)1252 个字符的正则表达式不再有效,我的 Perl html output 从字面上输出 4 个字符:'\x92' 和 '\x93' 等(至少这就是它在 utf8 模式下在浏览器上的显示方式,下载(ftp 不是 http)并在文本编辑器(textpad)中打开它是不同的,一个未定义的字符仍然存在,并且在 Firefox 默认(无内容类型标题)8859 模式下打开输出文件会呈现正确的字符)。

脚本开头的新 utf8 pragma 是:

使用 CGI qw(-utf8); 使用 open IO => ':utf8';

我知道这是由于 utf8 模式使字符成为双字节而不是单字节,并适用于 0x80 到 0xff 范围内的那些字符,阅读了与此相关的维基书籍上的文章,但是我不知道如何过滤它们。理想情况下,我知道我应该以 utf8 模式重新保存所有文档(因为平面文件数据库现在包含 8859 和 utf8 的混合),但是如果我要这样做的话,我首先需要某种过滤器.

对于内部的 2 字节存储,我可能是错误的,因为它似乎暗示 Perl 根据不同的情况处理非常不同的东西。

如果有人可以为我提供正则表达式解决方案,我将不胜感激。或者其他一些方法。数周来,我一直在为此烦恼,尝试了各种尝试,但黑客攻击失败了。通常需要替换大约 6 个 1252 字符,并且通过过滤器方法,我可以在 utf8 中重新保存整个翻转批次,而忘记曾经有一个 1252 ......

4

4 回答 4

2

Encoding::FixLatin专门用于帮助修复以与您相同的方式损坏的数据。

于 2011-10-21T14:55:48.353 回答
1

池上已经提到Encoding::FixLatin模块。

另一种方法是,如果您知道每个字符串将UTF-8 或 CP1252,但不是两者的混合,则将其作为二进制字符串读取并执行以下操作:

unless ( utf8::decode($string) ) {
    require Encode;
    $string = Encode::decode(cp1252 => $string);
}

与 Encoding::FixLatin 相比,这有两个小优点:将 CP1252 文本误解为 UTF-8 的可能性略低(因为整个字符串必须是有效的 UTF-8)以及用其他一些备用编码替换 CP1252 的可能性。一个相应的缺点是,由于某些其他原因,例如因为它们在多字节字符的中间被截断,此代码可能会在不完全有效的 UTF-8 字符串上回退到 CP1252。

于 2011-10-21T15:55:51.917 回答
1

您还可以使用Encode.pmfallback的支持。

use Encode qw[decode];

my $octets = "\x91 Foo \xE2\x98\xBA \x92";
my $string = decode('UTF-8', $octets, sub {
    my ($ordinal) = @_;
    return decode('Windows-1252', pack 'C', $ordinal);
});

printf "<%s>\n", 
  join ' ', map { sprintf 'U+%.4X', ord $_ } split //, $string;

输出:

<U+2018 U+0020 U+0046 U+006F U+006F U+0020 U+263A U+0020 U+2019>
于 2011-10-27T19:49:05.650 回答
0

您是否重新编码了数据文件?如果没有,以 UTF-8 格式打开它们将不起作用。您可以简单地将它们打开为

open $filehandle, '<:encoding(cp1252)', $filename or die ...;

一切(tm)都应该工作。

如果您确实重新编码,则似乎出现了问题,您需要分析它是什么并修复它。我建议使用 hexdump 来找出文件中的实际内容。文本控制台和编辑器有时会骗你,hexdump 从不说谎。

于 2011-10-21T11:53:46.273 回答