【问题标题】:Detect UTF-8 encoding (How does MS IDE do it)?检测 UTF-8 编码(MS IDE 是如何做到的)?
【发布时间】:2020-12-10 05:13:41
【问题描述】:

各种字符编码的一个问题是包含文件并不总是被清楚地标记。使用“字节顺序标记”或 BOM 标记某些内容的约定不一致。但本质上,您必须告诉文件编码是什么,才能准确读取它。

我们构建了读取源文件的编程工具,这让我们很伤心。我们有办法指定默认值,并嗅探 BOM 等。而且我们在约定和默认值方面做得很好。但是我们(我假设其他人)会挂断的地方是没有 BOM 标记的 UTF-8 文件。

最近的 MS IDE(例如,VS Studio 2010)显然会“嗅探”文件以确定它是否是 UTF-8 编码而没有 BOM。 (在工具业务中,我们希望与 MS 兼容,因为它们的市场份额,即使这意味着必须与他们一起越过“愚蠢”的悬崖。)我对他们使用什么特别感兴趣启发式(尽管启发式的讨论很好)?怎么可能是“对的”? (考虑以这种方式解释的 ISO8859-x 编码字符串)。

编辑:这篇关于检测字符编码/集的论文非常有趣: http://www-archive.mozilla.org/projects/intl/UniversalCharsetDetection.html

2012 年 12 月编辑:我们结束了对整个文件的扫描,以查看它是否包含任何违反 UTF-8 序列的内容……如果没有,我们将其称为 UTF-8。这个解决方案的坏处是,如果字符是 UTF-8,则必须处理两次。 (如果不是 UTF-8,这个测试可能会很快确定,除非文件发生在所有 7 位 ASCII 上,此时像 UTF-8 一样读取不会受到伤害)。

【问题讨论】:

  • 尝试以 UTF-8 格式读取整个文件要么是“成功的”,要么是遇到无效的字节序列。在某些时候,我以为我看到了一篇谈论误报可能性的文章,但我无法重新定位它。
  • 这个答案 (stackoverflow.com/a/4522251/120163) 声称对于相当短的字符序列有一些微小的“误报”率。我正在尝试确定我是否理解/相信它。
  • ... 上面的答案似乎假设从 Unicode 集中抽取的字符是随机的、平坦的分布,我高度怀疑这是错误的,所以我得出结论认为误报率很小的论点是错误的。 (它可能仍然很小)。
  • 没有一个 ISO-8859-x 文件中包含一个由 ASCII 包围的非 ASCII 字符将永远是有效的 UTF-8。大多数两字节非 ASCII 序列不是有效的 UTF-8。有一些现实生活中的字符串示例可能会被误解为 UTF-8,但整个文件不太可能只有这些字符串。
  • 如果你可以处理整个文件,为什么不检查它的有效 utf-8 编码呢?如果是,很可能是真的 utf-8。

标签: utf-8 character-encoding ide


【解决方案1】:

如果编码是 UTF-8,那么您在 0x7F 上看到的第一个字符必须是 UTF-8 序列的开头。所以测试它。这是我们使用的代码:

unc ::IsUTF8(unc *cpt)
{
    if (!cpt)
        return 0;

    if ((*cpt & 0xF8) == 0xF0) { // start of 4-byte sequence
        if (((*(cpt + 1) & 0xC0) == 0x80)
         && ((*(cpt + 2) & 0xC0) == 0x80)
         && ((*(cpt + 3) & 0xC0) == 0x80))
            return 4;
    }
    else if ((*cpt & 0xF0) == 0xE0) { // start of 3-byte sequence
        if (((*(cpt + 1) & 0xC0) == 0x80)
         && ((*(cpt + 2) & 0xC0) == 0x80))
            return 3;
    }
    else if ((*cpt & 0xE0) == 0xC0) { // start of 2-byte sequence
        if ((*(cpt + 1) & 0xC0) == 0x80)
            return 2;
    }
    return 0;
}

如果返回 0,则它不是有效的 UTF-8。否则跳过返回的字符数并继续检查下一个超过 0x7F 的字符。

【讨论】:

  • 我们做了一些与此基本相同的事情。不过,感谢您的详细回复。
  • 我会为纯 ascii 添加第四个案例:else if (*cpt & 0x80 == 0x00) return 1;
  • 您没有回答关于 MS 做什么的问题,但我怀疑我不太可能得到答案。您确实提供了一个简单的检查机制。我认为它并不完整,因为它会接受一些非 Unicode 序列(并非所有组合都是有效的),但它作为一种启发式方法非常好。所以,我给你的答案带来了好处。
  • @Jeremy Griffith I 转换器在 Java 方法 isUTF at this way ==> 结果在这部分不起作用 if ((buffer[0] & 0xF8) == 0xF0) { (and currentaFile 100%编码良好)为什么会发生这种情况?怎么了?如何解决这个问题?
【解决方案2】:

Visual Studio Code 使用jschardet,它返回猜测值和置信度。都是开源的,所以你可以检查代码。

https://github.com/microsoft/vscode/issues/101930#issuecomment-655565813

【讨论】:

    【解决方案3】:

    我们刚刚找到了解决方案 基本上,当您不知道文件/流/源的编码时,您需要检查整个文件和/或查找部分文本以查看是否获得 UTF-8 匹配。我看到这类似于某些抗病毒产品所做的,检查已知病毒子字符串的部分

    也许我建议您将调用应用于类似于我们在读取文件/流时所做的函数,逐行确定是否找到 UTF-8 编码

    请参考我们下面的帖子

    参考。 - https://stackoverflow.com/questions/17283872/how-to-detect-utf-8-based-encoded-strings

    【讨论】:

    • 您没有仔细阅读我的 EDIT 2012 年 12 月说明。这正是我所说的,我们做到了。您无需处理部分;你可以处理整个事情来决定。 (如果你还没有确定编码,那么逐行读取是什么意思?)
    • 很好,你做了和我们一样的事情,以及我们在帖子中解释的内容。分部读取的原因取决于使用情况;即,如果我正在制作一个刮刀并且我必须在列表视图中显示我刮取的部分内容,我不需要检测我得到的整个刮取的 HTML,而只是我想要在网格/控件中显示的文本部分。需要像我们所做的那样使用函数是因为你不能对已经 UTF 解码的东西进行 UTF 解码。即 DecodeUTF8("Societé") 将返回类似 Societ¿ 的东西,这是错误的。这就是为什么您首先需要检测字符串是否为 SocietÃ^
    • 此外,我们发现仅仅通过读取其 BOM 标头或检查其 UTF-8 声明(如果是 HTML)来确定文件的编码不够可靠,即您可能正在从数据库并且您不知道它是否是 UTF,如果有人只是在文本区域或文本框中复制/粘贴文本并且您的编码没有特别期望/编码来保存基于 UTF 的数据,则同样适用。我希望我们在帖子中所做的功能对其他人有所帮助。问候,迭戈
    • 基本上你无法赢得这场战争。由于某些位字符串可以是 UTF-8 和 EBCDIC,因此您真正知道的唯一方法就是被告知。有两种方法可以告知:1)测试容器外的元数据(容易且经常丢失),2)标记文件的元数据(BOM 等或文件属性)。但人们似乎讨厌 BOM 样式的标记。剩下的是混乱,这是我们所拥有的,并且当之无愧的社区。智商似乎不是累加的。
    • 那你有什么建议?因为,最终,我们都必须处理“我们不知道”来源和/或不被告知它具有哪种编码的字符串。问自己这个问题就是我提出这个功能的原因。我知道它可以有效地检测大多数常用语言中的标点符号和符号,我不能保证它可以检测到其他真正不常见的符号,但是我的功能可以检测到 áéíóú、基本 àèìòù、äëïöü 和其他符号。我明白你的意思,但我们必须做一些事情,或者至少以某种方式依赖解决方法
    猜你喜欢
    • 2013-10-30
    • 2012-04-26
    • 2020-09-15
    • 2017-04-20
    • 1970-01-01
    • 2020-04-28
    • 2012-03-07
    • 1970-01-01
    • 2010-10-26
    相关资源
    最近更新 更多