← 返回题目列表

UTF-8 编码验证如何用位掩码判断字节前缀?

中等 第 26 / 26 题 更新于 2026/08/01
位运算UTF-8掩码字节前缀

简化版

UTF-8 验证要看每个字节的高位前缀。单字节以 0 开头,多字节首字节以 110/1110/11110 开头,后续字节必须以 10 开头。用位掩码判断这些前缀,并维护还需要多少个 continuation byte。

详细版

遍历数组中的每个整数,只取低 8 位。若当前不在多字节字符内部,就根据高位模式判断这是 1、2、3、4 字节字符;若在内部,则当前字节必须满足 (byte & 0b11000000) == 0b10000000。维护 remaining 表示还需要几个后续字节。

时间复杂度 O(n),空间复杂度 O(1)。这题重点是二进制前缀匹配,不是字符集语义。

完整版教学

一、UTF-8 的字节前缀规则

UTF-8 用不同前缀表示一个字符占几个字节:

字节类型前缀
1 字节字符0xxxxxxx
2 字节首字节110xxxxx
3 字节首字节1110xxxx
4 字节首字节11110xxx
后续字节10xxxxxx

验证时只需要判断这些高位模式是否匹配。

二、为什么只看低 8 位

题目输入通常是整数数组,但每个整数表示一个字节。一个字节只有 8 位,所以要关注低 8 位。

b = data[i] & 0xFF

如果平台保证 0 <= data[i] <= 255,这一步可以省略,但写出来语义更清楚。

三、如何判断后续字节

后续字节必须以 10 开头。用掩码取最高两位:

(b & 0b11000000) == 0b10000000

十六进制写法:

(b & 0xC0) == 0x80

记忆钩子:UTF-8 continuation byte 的身份证是高两位 10

四、如何判断首字节长度

当不在等待后续字节时,看首字节前缀:

0xxxxxxx  => remaining = 0
110xxxxx  => remaining = 1
1110xxxx  => remaining = 2
11110xxx  => remaining = 3
其他      => 非法

可以用从高位开始数连续 1 的数量,也可以直接用掩码匹配固定模式。

五、代码模板

boolean validUtf8(int[] data) {
    int remaining = 0;
    for (int x : data) {
        int b = x & 0xFF;
        if (remaining > 0) {
            if ((b & 0xC0) != 0x80) return false;
            remaining--;
        } else {
            if ((b & 0x80) == 0) {
                remaining = 0;
            } else if ((b & 0xE0) == 0xC0) {
                remaining = 1;
            } else if ((b & 0xF0) == 0xE0) {
                remaining = 2;
            } else if ((b & 0xF8) == 0xF0) {
                remaining = 3;
            } else {
                return false;
            }
        }
    }
    return remaining == 0;
}

最后必须确认 remaining==0,否则说明数据在一个多字节字符中途结束。

六、用例子推演

[197,130,1]

197 = 11000101 => 2 字节首字节,remaining=1
130 = 10000010 => 合法后续,remaining=0
1   = 00000001 => 单字节

所以合法。

[235,140,4]

235 = 11101011 => 3 字节首字节,remaining=2
140 = 10001100 => 合法后续,remaining=1
4   = 00000100 => 不是 10 开头,非法

七、常见误区与追问

  • 误区:只检查首字节,不检查后续字节。 多字节字符的后续字节必须全部以 10 开头。
  • 误区:最后不检查 remaining。 数据可能在多字节字符中途结束。
  • 误区:把 11111xxx 当合法。 UTF-8 最多 4 字节,111110xx 这类前缀不合法。
  • 追问:为什么用 0xC0 判断后续字节? 0xC011000000,能取出最高两位。
  • 追问:输入整数超过 255 怎么办? 应只取低 8 位或按题目约束判断非法。
  • 追问:复杂度是多少? 每个字节处理一次,时间 O(n)

八、加强记忆

UTF-8 验证就是前缀状态机。首字节决定还欠几个后续字节,后续字节必须是 10xxxxxx。掩码 0x80/0xE0/0xF0/0xF8 判断首字节,0xC0==0x80 判断后续字节。最后 remaining 必须归零。