leetcode utf-8编码正误

下面的章节会给出三个例子来解释题目,如果你很清楚这道题了,那你可以直接跳过。

题述中给了两个例子来帮助你理解 UTF-8 字符集的规则。对于很多人来说这两个例子是不够的,所以接下来做的第一件事就是来理解题述中给的规则,同时再来看一个例子来帮助我们更好地理解这道题。那就开始吧。

一个合法的 UTF-8 字符的长度为 1-4 字节。
对于 1 字节的字符,字节的第一位设为 0,后面 7 位为这个符号的 unicode 码。
对于 n 字节的字符 (n > 1),第一个字节的前 n 位都为 1,第 n+1 位为 0,后面字节的前两位一律都为 10。
输入是代表字符的整数数组。我们要判断数组中的数能不能表示成数个合法的 UTF-8 字符。在第一个的例子里面可以看到,数组上的可以表示称数个合法的 UTF-8 字符,因此这个数组是合法的。
有一个点需要注意的是,数组中的整数是有可能大于255的。我们都知道 8 比特能表示的最大整数为255。假如数组中有一个数为 476,那我们该怎么处理呢? 根据题述例子中的说明,我们只需要考虑每个整数中 最高8位 就可以了。
现在规则已经搞清楚了,让我们先来看题述中例子,接下里再看一些可能造成困惑的其他例子。

例一

data = [197, 130, 1]
首先把这个数组表示成二进制的形式

11000101 10000010 00000001
记住,对于一个 n 字节长的 UTF-8 字符来说,第一个字节的前 n 位都为 1,第 n+1 位为 0,后面字节的前两位一律都为 10。

[1 1 0] 0 0 1 0 1
↑ ↑
第一个字节的前两个比特值都是 1,1 后面紧接着一个 0。这是一个合法 UTF-8 字符的开始。同时从中可知这是一个 2 字节长的 UTF-8 字符。这也就意味着序列中接下来的字节一定是 10xxxxxx 这样的形式。

[1 1 0] 0 0 1 0 1 [1 0] 0 0 0 0 1 0
↑ ↑ ↑ ↑
是的,确实是遵循了规则。因此数组中 197 130 这两个数共同组成了一个合法的 2 字节 UTF-8 字符。既然数组中还有元素,继续以同样的方式检查。接下来的整数是 1,先把它变成二进制表示。

00000001
在这里最高比特位是 0,那么它只能满足 1 字节 UTF-8 字符的规则了。让我们来回顾一下这个规则:

对于 1 字节的字符,字节的第一位设为 0,后面 7 位为这个符号的 unicode 码。

[0] 0 0 0 0 0 0 1

显然,整数 1 本身就是一个合法的 1 字节 UTF-8 字符。这时候数组已经没有剩余数要处理了,从前面的分析可知整个数组表示的是两个合法的 UTF-8 字符,因此需要返回 True。

例子二

[235, 140, 4]
这是题述中的第二个例子。照样先把这个整数数组的转成二进制表示。

11101011 10001100 00000100
从数组的第一个整数开始。第一个字节会告诉我们这个 UTF-8 字符的长度,同时会告诉我们接下里该处理多少个字节来完全解析当前的 UTF-8 字符。

[1 1 1 0] 1 0 1 1
↑ ↑
可以看到前四个比特为 1110。这意味着这个 UTF-8 字符总共有 3 字节。记住,我们可以从第一个字节中知晓这个潜在 UTF-8 字符的长度。

对于 n 字节的字符 (n > 1),第一个字节的前 n 位都为 1,第 n+1 位为 0。

根据这个规则我们知道了第一个 UTF-8 字符是长度为 3 字节。第一个字节已经处理过了,还需要处理剩下的两个字节。我们来看一下这个数组中剩下的两个字节。

[1 0] 0 0 1 1 0 0 0 0 0 0 0 1 0 0
↑ ↑ ↑ (WRONG!)
第一个字节遵循了 10xxxxxx 规则,但是第二个字节违反了这个规则。根据第一个字节 11101011,这只能是一个 3 字节 UTF-8 字符。但是最后一个字节违反了规则。因此,这是一个非法字节,这也就意味着可以直接返回 False了。

例三

在看题解之前我们来看最后一个例子。在讨论区可以看到这个例子对很多人造成了困惑。

下面就是这个例子了:

[250,145,145,145,145]
照旧把数组中所有的整数转成二进制表示。

11111010 10010001 10010001 10010001 10010001
和前两个例子一样,首先看第一个字节来获取当前这个 UTF-8 字符的长度。从第一个字节中可以知道这个 UTF-8 字符的长度是 5 字节。

[1 1 1 1 1 0] 1 0
↑ ↑
如果这是一个合法的 UTF-8 字符,那么接下来的四个字节必须遵守 10xxxxxx 规则。我们来看一下接下来的四个字节吧。

  1. [1 0] 0 1 0 0 0 1
  2. [1 0] 0 1 0 0 0 1
  3. [1 0] 0 1 0 0 0 1
  4. [1 0] 0 1 0 0 0 1
    可以看到,这四个字节都是遵守 10xxxxxx 规则。那为什么这个例子需要返回 False 呢? 这是因为你忽略了题目给的第一个规则。

题述中的第一个规则,很清楚地说了 “一个合法的 UTF-8 字符的长度为 1-4 字节。”

从第一个字节就知道了这个 UTF-8 字符将包含 5 字节 了,这也就意味着这个字符绝对是非法的。这也就是为什么对于这个例子应该返回 False了。

作者:LeetCode
链接:https://leetcode-cn.com/problems/utf-8-validation/solution/utf-8-bian-ma-yan-zheng-by-leetcode/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

class Solution {
public:
    bool validUtf8(vector<int>& data) {
        int p=0,cnt;
        while(p<data.size())
        {
            cnt=0;
            //通过与运算确定首个字节蕴含的字节长度
            if((data[p]&0b10000000)==0)
            {
                cnt=0;
            }
            else if((data[p]&0b11100000)==0b11000000)
            {
                cnt=1;
            }
            else if((data[p]&0b11110000)==0b11100000)
            {
                cnt=2;    
            }
            else if((data[p]&0b11111000)==0b11110000)cnt=3;
            //0b后面的比data[p]&x  中的1少一位
            else 
            return false;
            p++;
            //本身首个8位占一次,p+1
            while(p<data.size()&&cnt)
            //某一个原数读取完毕,则cnt=0,p是关于原数所在数组中的位置
            {
                if((data[p]&0b11000000)!=0b10000000) break; 
                p++;
                
                cnt--;
                

            }
            //a1 b1 b1  a2 b2 b2 b2这种情况,读完b1,cnt清零,p不清零 
            if(cnt!=0) return false;
            //cnt没清零,出现错误



        }
        return true;
        //所有情况都通过,返回true
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值