【问题标题】:How can I determine if a file contains UTF-8 like characters如何确定文件是否包含类似 UTF-8 的字符
【发布时间】:2019-09-12 18:49:15
【问题描述】:

我正在尝试编写一个程序,它将文件作为输入,迭代文件,然后检查文件是否包含 UTF-8 编码字符。

但是我不确定如何解决 UTF-8 编码的问题。我理解编码背后的基本概念,它可以存储在 1-4 个字节中,其中 1 个字节只是 ASCII 表示(0-127)。

1 个字节:0xxxxxxx

对于其余部分,我相信模式是这样的:

2 个字节:110xxxxxx 10xxxxxx

3 个字节:1110xxxx 10xxxxxx 10xxxxxx

4个字节:11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

但是,我很难意识到如何在 C 代码中实现这一点。我知道我将如何迭代文件,如果 UTF-8 编码的谓词成立,我会做一些事情:

while ((check = fgetc(fp)) != EOF) {
        if (*) {
        // do something to the code
    }
}

但是,我不确定如何将 UTF-8 的编码实际修改和实现为 C(或任何没有内置函数的语言,例如 C# UTF8Encoding)。

作为一个使用与 ASCII 类似的逻辑的简单示例,我只需遍历每个字符(指向检查变量)并验证它是否在 ASCII 字符限制内:

if (check >= 0 && check <= 127) {
    // do something to the code
}

谁能尝试向我解释我将如何使用类似的逻辑,只有在尝试确定检查变量是否指向 UTF-8 编码字符时?

【问题讨论】:

  • if (ch&amp;0xe0==0xc0){...one byte will follow...} 等等...
  • 只需解码代码点。然后检查它们的编码是否最短。
  • @wildplasser 能否详细说明一下 $(ch&xe0==0xc0)$ 的内部结构,我不太清楚如何理解这个?
  • 字面意思是ANDch0x11100000 的内容,并用0x11000000 测试相等性。
  • @wildplasser — 我可以假设您的意思是if ((ch &amp; 0xE0) == 0xC0),问题在于额外的括号而不是大写或空格。目前{…}中的代码不会被执行,因为0xE0不等于0xC0,所以&amp;的RHS为0,所以ch &amp; 0的结果为0。

标签: c utf-8


【解决方案1】:
if ( (ch & 0x80) == 0x0 ) {
  //ascii byte
}
else if ( (ch & 0xe0) == 0xc0 ) {
  // 2 bytes
}
else if ( (ch & 0xf0) == 0xe0 ) {
 // 3 bytes
}
else if ( (ch & 0xf8) == 0xf0 ) {
  // 4 bytes
}

您想按位 & 前 x 位并检查前 x-1 位是否为 1。它有助于以二进制写出数字并继续。

【讨论】:

  • 感谢您的解决方案,经过一些书面工作示例后,我清楚地了解了这是如何工作的。但是,是否有一个直观的理由为什么您会与所呈现的值完全一致?例如,为什么 ((ch & 0xf8) == 0xf0) 是检查 4 字节等的正确方法。
  • @NewProgrammer 4 字节案例:我们正在尝试识别具有 11110xxx 模式的字节,即 4 个 1 和 1 个零,总共 5 位。我们 & 用 0xf8 (0b11111000) 选择我们的 char 的高 5 位——我们感兴趣的位。现在我们必须检查这五个位中的前四个是 1,最后一个是 0,所以我们测试与 0xf0 (0b11110000) 相等。其他情况类似,但检查的位数更少。
【解决方案2】:

UTF-8 并不难,但它比您意识到的和 jpsalm 的回答所暗示的要严格。如果你想测试它是否是有效的 UTF-8,你需要确定它是否符合定义,在RFC 3629 中用 ABNF 表示:

UTF8-octets = *( UTF8-char )
UTF8-char   = UTF8-1 / UTF8-2 / UTF8-3 / UTF8-4
UTF8-1      = %x00-7F
UTF8-2      = %xC2-DF UTF8-tail
UTF8-3      = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) /
              %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail )
UTF8-4      = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) /
              %xF4 %x80-8F 2( UTF8-tail )
UTF8-tail   = %x80-BF

或者,您可以对“非最短形式”和其他东西(替代范围)进行大量数学检查,但这是一个巨大的痛苦,并且极易出错。我见过的几乎每一个以这种方式完成的实现,即使是在广泛使用的主要软件中,至少在一件事情上都是完全错误的。接受 UTF-8 的状态机很容易实现,并且很容易验证它是否与正式定义匹配。 https://bjoern.hoehrmann.de/utf-8/decoder/dfa/

详细描述了一个漂亮、干净、可读的

【讨论】:

  • 您已成功证明 UTF-8 的功能比许多人想象的要多,但这似乎并没有解决问题。
  • @AdrianMcCarthy:“我正在尝试编写一个程序,它将文件作为输入,迭代文件,然后检查文件是否包含 UTF-8 编码字符。” fgetc 读取的每个字节上转换。
  • 我相信问题的其余部分表明编写状态机是 OP 遇到困难的部分。
猜你喜欢
  • 2013-04-23
  • 2018-09-03
  • 2012-02-06
  • 1970-01-01
  • 2023-03-17
  • 2020-03-13
  • 2012-12-23
  • 2016-04-24
  • 2018-09-21
相关资源
最近更新 更多