检测UTF中的实际字符集编码

时间:2015-01-08 03:48:03

标签: encoding utf-8 character-encoding

需要使用某种映射或启发式方法检测字符串编码的好工具。

例如String:áÞåàÐÝØÒ ÜÝÞÓÞ ßàØÛÞÖÕÝØÙ Java, ÜÞÖÝÞ ×ÐÝïâì Òáî ÔÞáâãßÝãî ßÐÜïâì

预期:сохранив много приложений Java, можно занять всю доступную память

编码是" ISO8859-5"。当我试图用下面的libs检测它时,结果是" UTF-8"。很明显,字符串是以utf格式保存的,但是有没有任何启发式的方式使用符号映射来分析字符并将它们与正确的编码匹配?

使用通常的编码检测库:

- enca (aptitude install enca)
- chardet (aptitude install chardet)
- uchardet (aptitude install uchardet)
- http://tika.apache.org/
- http://npmjs.com/package/detect-encoding
- libencode-detect-perl
- http://www-archive.mozilla.org/projects/intl/UniversalCharsetDetection.html
- http://jchardet.sourceforge.net/
- http://grepcode.com/snapshot/repo1.maven.org/maven2/com.googlecode.juniversalchardet/juniversalchardet/1.0.3/
- http://lxr.mozilla.org/seamonkey/source/extensions/universalchardet/src/
- http://userguide.icu-project.org/
- http://site.icu-project.org

2 个答案:

答案 0 :(得分:1)

您需要打开UTF-8编码并然后将其传递给字符编码检测库。

如果随机8位数据被编码为UTF-8(假设身份映射,即假设C4字节代表U + 00C4,就像ISO-8859-1及其超集Windows 1252的情况一样),你最终会得到像

这样的东西
Source:  8F    0A 20 FE    65
Result:  C2 8F 0A 20 C3 BE 65

(因为U + 008F的UTF-8编码是C2 8F,而U + 00FE是C3 BE)。您需要还原此编码才能获取源字符串,以便您可以识别其字符编码。

在Python中,类似

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import chardet

mystery = u'áÞåàÐÝØÒ ÜÝÞÓÞ ßàØÛÞÖÕÝØÙ Java, ÜÞÖÝÞ ×ÐÝïâì Òáî ÔÞáâãßÝãî ßÐÜïâì'
print chardet.detect(mystery.encode('cp1252'))

结果:

{'confidence': 0.99, 'encoding': 'ISO-8859-5'}

在Unix命令行中,

vnix$ echo 'áÞåàÐÝØÒ ÜÝÞÓÞ ßàØÛÞÖÕÝØÙ Java, ÜÞÖÝÞ ×ÐÝïâì Òáî ÔÞáâãßÝãî ßÐÜïâì' |
> iconv -t cp1252 | chardet
<stdin>: ISO-8859-5 (confidence: 0.99)

iconv -t cp1252 file | chardet解码文件并将其传递给chardet

(为了在命令行中成功运行,您需要正确设置环境以进行透明的Unicode处理。我假设您的shell,终端和您的语言环境已经配置充分。请尝试最近的Ubuntu Live如果您的常规环境在20世纪陷入困境,那就是CD或其他东西。)

在一般情况下,您无法知道错误应用的编码是CP 1252,但实际上,我认为它在大多数情况下都是正确的(例如,在此方案中产生正确的结果)。在最坏的情况下,您必须遍历所有可用的传统8位编码并全部尝试,然后查看来自chardet的置信度最高的那些编码。然后,上面的示例也将更加复杂 - 从传统的8位数据到UTF-8的映射将不再是简单的身份映射,而是涉及转换表(例如,字节F5可能任意对应U + 0092或其他)。

(顺便说一下,iconv -l会吐出一长串别名,所以如果你把它作为输入,你会得到很多基本相同的结果。但这里是一个快速的临时尝试来修复你的奇怪的Perl脚本。

#!/bin/sh
iconv -l |
grep -F -v -e UTF -e EUC -e 2022 -e ISO646 -e GB2312 -e 5601 |
while read enc; do
    echo 'áÞåàÐÝØÒ ÜÝÞÓÞ ßàØÛÞÖÕÝØÙ Java, ÜÞÖÝÞ ×ÐÝïâì Òáî ÔÞáâãßÝãî ßÐÜïâì' |
    iconv -f utf-8 -t "${enc%//}" 2>/dev/null |
    chardet | sed "s%^[^:]*%${enc%//}%"
done |
grep -Fwive ascii -e utf -e euc -e 2022 -e None |
sort -k4rn

输出仍然包含很多糠,但是一旦删除它,判决很简单。

在这种情况下尝试任何多字节编码(例如UTF-16,ISO-2022,GB2312,EUC_KR等)是没有意义的。如果您将一个字符串成功转换为其中一个,那么结果肯定是 in 该编码。这超出了上述问题的范围:使用错误的转换表将字符串从8位编码转换为UTF-8。

返回ascii的人肯定做错了什么;他们中的大多数都会收到一个空输入,因为iconv失败并出现错误。在Python脚本中,错误处理会更简单。)

答案 1 :(得分:0)

字符串

сохранив много приложений Java, можно занять всю доступную память

以ISO8859-5编码为字节

E1 DE E5 E0 D0 DD D8 D2 20 DC DD DE D3 DE 20 DF E0 D8 DB DE D6 D5 DD D8 D9 20 4A 61 76 61 2C 20 DC DE D6 DD DE 20 D7 D0 DD EF E2 EC 20 D2 E1 EE 20 D4 DE E1 E2 E3 DF DD E3 EE 20 DF D0 DC EF E2 EC

字符串

áÞåàÐÝØÒ ÜÝÞÓÞ ßàØÛÞÖÕÝØÙ Java, ÜÞÖÝÞ ×ÐÝïâì Òáî ÔÞáâãßÝãî ßÐÜïâì

以ISO-8859-1编码为字节

E1 DE E5 E0 D0 DD D8 D2 20 DC DD DE D3 DE 20 DF E0 D8 DB DE D6 D5 DD D8 D9 20 4A 61 76 61 2C 20 DC DE D6 DD DE 20 D7 D0 DD EF E2 EC 20 D2 E1 EE 20 D4 DE E1 E2 E3 DF DD E3 EE 20 DF D0 DC EF E2 EC

看起来很熟悉?它们是相同的字节,只是由不同的字符集进行不同的解释。

任何查看这些字节的工具都无法自动告诉您字符集,因为它们在两个字符集中都是完全有效的字节。在解释字节时,您必须告诉工具使用哪个字符集。

任何告诉您此特定字节序列被编码为UTF-8的工具都是错误。这些不是有效的UTF-8字节。