问题

在工作中似乎没有一周没有一些编码相关的conniption,灾难或灾难。这个问题通常来自程序员,他们认为他们可以在不指定编码的情况下可靠地处理"文本"文件。但你不能。

因此,已经决定从此以后禁止文件的名称以*.txt*.text结尾。我们的想法是,这些扩展误导了偶然程序员对编码的沉闷,这会导致处理不当。没有任何扩展几乎会更好,因为至少你知道你不知道你有什么。

但是,我们并不是那么远。相反,你需要使用以编码结尾的文件名。因此,对于文本文件,例如,这些将类似于README.ascii,README.latin1,README.utf8等。

对于需要特定扩展名的文件,如果可以在文件本身内部指定编码,例如在Perl或Python中,那么你应该这样做。对于像Java源这样的文件,文件内部不存在此类工具,你将在扩展名之前放置编码,例如SomeClass-utf8.java

对于输出,UTF-8强制为**,优先级为**。

但是对于输入,我们需要弄清楚如何处理代码库中名为*.txt的数千个文件。我们想重命名所有这些以符合我们的新标准。但我们不可能全都注意它们。所以我们需要一个真正有用的库或程序。

它们有各种ASCII,ISO-8859-1,UTF-8,Microsoft CP1252或Apple MacRoman。虽然我们知道我们可以判断某些东西是否为ASCII,并且我们知道某些东西是否可能是UTF-8,但我们对8位编码感到困惑。因为我们在混合的Unix环境(Solaris,Linux,Darwin)中运行,大多数桌面都是Mac,所以我们有很多烦人的MacRoman文件。而这些尤其是一个问题。

一段时间以来,我一直在寻找一种方法来以编程方式确定哪一个

  • ASCII
  • ISO-8859-1
  • CP1252
  • MacRoman
  • UTF-8

文件在,我还没有找到一个程序或库,可以可靠地区分这三种不同的8位编码。我们可能单独拥有超过一千个MacRoman文件,因此我们使用的任何字符集检测器都必须能够嗅出这些文件。我没看过任何东西可以解决这个问题。我对ICU charset detector library寄予厚望,但它无法处理MacRoman。我也看过模块在Perl和Python中做同样的事情,但是一次又一次它总是相同的故事:不支持检测MacRoman。

我正在寻找的是一个现有的库或程序,它可靠地确定文件所在的五种编码中的哪一种 - 并且最好是更多。特别是它必须区分我引用的三个3位编码,,特别是MacRoman.这些文件超过99%的英文文本;其他语言中有一些,但并不多。

如果是库代码,我们的语言首选项是Perl,C,Java或Python,并且按此顺序。如果它只是一个程序,那么我们并不关心它是什么语言,只要它是完整的源代码,在Unix上运行,并且完全没有阻碍。

有没有其他人有这个随机编码的遗留文本文件的问题?如果是这样,你是如何尝试解决它的,你有多成功?这是我的问题中最重要的方面,但我也感兴趣的是你是否认为鼓励程序员用这些文件的实际编码来命名(或重命名)他们的文件将有助于我们避免将来出现这个问题。有没有人试图在制度基础上强制执行这个,如果是的话,是否成功,为什么?

是的,我完全理解为什么鉴于问题的性质,人们无法保证给出明确的答案。对于没有足够数据可用的小文件尤其如此。幸运的是,我们的文件很少。除了randomREADME文件外,大多数的大小范围为50k到250k,而且许多都是更大的。任何超过几K的东西都保证是英文的。

问题领域是生物医学文本挖掘,因此我们有时会处理广泛且极大的语料库,就像所有PubMedCentral的Open Access资源库一样。一个相当庞大的文件是BioThesaurus 6.0,为5.7千兆字节。这个文件特别烦人,因为它几乎都是UTF-8。然而,我相信,有些numbskull会在其中插入几行8位编码 - 微软CP1252。在你旅行之前需要一段时间。 :(


#1 热门回答(85 赞)

首先,简单的案例:

ASCII

如果你的数据不包含0x7F以上的字节,则它是ASCII。 (或者是7位ISO646编码,但这些编码非常过时。)

UTF-8

如果你的数据验证为UTF-8,那么你可以安全地假设itisUTF-8。由于UTF-8严格的验证规则,误报极为罕见。

ISO-8859-1对比windows-1252

这两种编码之间的唯一区别是ISO-8859-1具有C1控制字符,其中windows-1252具有可打印的字符€,ƒ"...†‡‰Š<ŒŽ''""• - 〜™š> œžŸ。我见过很多使用弯引号或短划线的文件,但没有使用C1控制字符的文件。所以不要打扰他们,或ISO-8859-1,只需检测windows-1252。

那现在只留下一个问题。

#你如何区分MacRoman和cp1252?

这比较棘手。

##未定义的字符

在windows-1252中不使用字节0x81,0x8D,0x8F,0x90,0x9D。如果它们出现,则假设数据是MacRoman。

##相同的字符

两个编码中的字节0xA2(¢),0xA3(£),0xA9(©),0xB1(±),0xB5(μ)恰好相同。如果这些是唯一的非ASCII字节,那么无论选择MacRoman还是cp1252都无关紧要。

##统计方法

计算你知道为UTF-8的数据中的字符(非字节!)频率。确定最常用的字符。然后使用此数据确定cp1252或MacRoman字符是否更常见。

例如,在我刚刚对100篇随机英文维基百科文章进行的搜索中,最常见的非ASCII字符是·•–é°®’èö—。基于这个事实,

  • 字节0x92,0x95,0x96,0x97,0xAE,0xB0,0xB7,0xE8,0xE9或0xF6表示windows-1252。
  • 字节0x8E,0x8F,0x9A,0xA1,0xA5,0xA8,0xD0,0xD1,0xD5或0xE1表示MacRoman。

计算cp1252建议字节和MacRoman建议字节,并选择最大的字节。


#2 热门回答(10 赞)

Mozilla nsUniversalDetector(Perl绑定:Encode::Detect/Encode::Detect::Detector)经过百万倍的证明。


#3 热门回答(7 赞)

我尝试这种启发式(假设你已经排除了ASCII和UTF-8):

  • 如果根本没有出现0x7f到0x9f,则可能是ISO-8859-1,因为这些很少使用控制代码。
  • 如果批次出现0x91到0x94,则可能是Windows-1252,因为这些是"智能引号",到目前为止,该范围内最有可能用于英文文本的字符。更确切地说,你可以找对子。
  • 否则,它是MacRoman,特别是如果你看到很多0xd2到0xd5(这是排版引号在MacRoman中)。

边注:

对于像Java源这样的文件,文件内部不存在这样的工具,你将把编码放在扩展名之前,例如SomeClass-utf8.java
不要这样做!!
Java编译器期望文件名与类名匹配,因此重命名文件将使源代码无法编译。正确的做法是猜测编码,然后使用native2asciitool将所有非ASCII字符转换为Unicode escape sequences


原文链接