【问题标题】:Iterate backwards through a utf8 multibyte string通过 utf8 多字节字符串向后迭代
【发布时间】:2025-12-11 18:35:01
【问题描述】:

我使用此函数is_utf8https://*.com/a/1031773/275677 的略微修改版本从字符数组中提取 UTF8 序列,返回序列和其中的字节数,以便我可以以这种方式迭代字符串。

但是我现在想在字符串 (char *) 上迭代向后。最好的方法是什么?


我的猜测是尝试将字符串的最后四个、三个、两个和一个字节分类为utf8(四次)并选择最长的。

但是,utf8 是否存在歧义?例如,aaaabb 解析为 aaaa.bb 是否也可以被解析(向后)为 aa.aabb,其中 aaaaaabbaabb 是有效的 utf8 序列?

【问题讨论】:

  • 对于 Windows,我会使用 MultiByteToWideChar() 将字符串转换为 Unicode,然后进行简单的迭代。
  • UTF-8 绝不含糊。这就是 UTF-8 的重点。

标签: c string utf-8 iteration


【解决方案1】:

字符串由一系列 UTF-8 序列组成。所有 UTF-8 序列:

  • EITHER 仅由一个八位字节(你和我的字节)组成,高位清晰

  • OR由一个八位组组成,其中两个最高位设置,然后是一个或多个八位组,位 7 设置和位 6 清除。

详情请见http://en.wikipedia.org/wiki/Utf8#Description

所以你需要做的是检查相关字符是否设置了第 7 位和清除了第 6 位,如果是则退一步,注意不要超出字符串的开头(注意如果字符串是格式良好,这不会发生)。

未经测试的 C-ish 伪代码:

char *
findPrevious (const char *ptr, const char *start)
{
    do
    {
        if (ptr <= start)
            return NULL; /* we're already at the start of the string */
        ptr--;
    } while ((*ptr & 0xC0) == 0x80);
    return ptr;
} 

【讨论】:

  • 第二个条件错了。您的意思是第 7 位已设置且 第 6 位 已清除(假设您从 0 开始计数)。
  • @R.. doh - 谢谢 - 已修复。我认为伪代码是对的。
  • +1 思路:1) 如果假定字符串格式正确,则(ptr &lt;= start) 不必在循环中,而是在循环之前。 2 :) 也许const char *
【解决方案2】:

这看起来很有帮助。从内存的深度我记得,您可以通过在每个字节的前一位或两位达到峰值来判断 - 这使得查看字符串应该有多长变得微不足道,然后使用原始函数来验证它。

UTF-8 字符要么是最左边为 0 的单个字节,要么是第一个字节的最左边为 1..10 的多个字节...(左边有 1 的数量2 或更多)后跟 10... 形式的连续字节(即左侧的单个 1)。假设您的字符串格式正确,您可以遍历所有字节并在每次看到不是 10 形式的字节时增加“字符数”... - 即仅计算所有 UTF-8 中的第一个字节字符。

https://*.com/a/7108478/275677

还有http://en.wikipedia.org/wiki/UTF-8#Description的表格

【讨论】: