Google Interview - Valid UTF-8 Character
http://algorithmguru.com/blog/?p=148
1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。
2)对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。
0xxxxxxx是一个合法的单字节UTF8编码。
110xxxxx 10xxxxxx是一个合法的2字节UTF8编码。
1110xxxx 10xxxxxx 10xxxxxx是一个合法的3字节UTF8编码。
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx是一个合法的4字节UTF8编码。
https://reeestart.wordpress.com/2016/06/23/google-utf8-validation/
Read full article from Google Interview - Valid UTF-8 Character
http://algorithmguru.com/blog/?p=148
UTF-8 is a variable-length encoding of letters or runes. If the most significant bit of the first byte is 0, the letter is 1 byte long. Otherwise, its length is the number of leading 1’s in the first byte. If a letter is more than one byte long, all subsequent runes start with 10. Here’s a chart:
UTF-8 encoding scheme is described below:
0XXXXXXX = this is the entire rune
10XXXXXX = this is a continuation of the rune from the previous byte
110XXXXX = this is the start of a 2-byte rune.
1110XXXX = this is the start of a 3-byte rune.
11110XXX = this is the start of a 4-byte rune.
111110XX = this is the start of a 5-byte rune.
1111110X = this is the start of a 6-byte rune.
11111110 = this is the start of a 7-byte rune.
11111111 = this is the start of a 8-byte rune.
10XXXXXX = this is a continuation of the rune from the previous byte
110XXXXX = this is the start of a 2-byte rune.
1110XXXX = this is the start of a 3-byte rune.
11110XXX = this is the start of a 4-byte rune.
111110XX = this is the start of a 5-byte rune.
1111110X = this is the start of a 6-byte rune.
11111110 = this is the start of a 7-byte rune.
11111111 = this is the start of a 8-byte rune.
For example, a 3-byte rune would be 1110XXXX 10XXXXXX 10XXXXXX.
UTF-8是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。UTF-8的编码规则很简单,只有二条:1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。
2)对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。
0xxxxxxx是一个合法的单字节UTF8编码。
110xxxxx 10xxxxxx是一个合法的2字节UTF8编码。
1110xxxx 10xxxxxx 10xxxxxx是一个合法的3字节UTF8编码。
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx是一个合法的4字节UTF8编码。
bool valid_utf8(const vector<unsigned char>& data) {int size = 0;for(auto c : data) {if(size == 0) {if((c >> 5) == 0b110) size = 1;else if((c >> 4) == 0b1110) size = 2;else if((c >> 3) == 0b11110) size = 3;else if(c >> 7) return false;} else {if((c >> 6) != 0b10) return false;--size;}}return size == 0;}
https://reeestart.wordpress.com/2016/06/23/google-utf8-validation/
UTF8编码定义为 1~8个byte:
1byte以0开头,0XXXXXXX
2byte以110开头,110XXXXX
3byte以1110开头,1110XXXX
4byte以11110开头,11110XXX
5byte以111110开头,111110XX
6byte以1111110开头,1111110X
7byte以11111110开头
8byte以11111111开头
1byte以0开头,0XXXXXXX
2byte以110开头,110XXXXX
3byte以1110开头,1110XXXX
4byte以11110开头,11110XXX
5byte以111110开头,111110XX
6byte以1111110开头,1111110X
7byte以11111110开头
8byte以11111111开头
10XXXXXX这种作为连续多个byte的组成部分,比如3byte 就是1110XXXX 10XXXXXX 10XXXXXX。
要求就是给一个byte[]数组,判断它是否符合编码定义。
stack overflow上很好的解法。
思路就是看开头的byte,根据开头来判断byte数组应该有的长度,再和实际长度比较,以及后面的组成部分是否都start with 10.
而判断开头byte的方法有很多种,最简单就是brute force扫一遍看有几个1. 但是stack overflow上面那个bit manipulation的方法很巧妙。
比如2byte, 就用0b1110000和实际byte[0]做AND, 如果是valid的编码,得到的结果一定是0b11000000:
0b11100000
& 0bXXXXXXXX
= 0b11000000
& 0bXXXXXXXX
= 0b11000000
[Node]
另外注意utf8定义长度超过6的都是不合法的。
另外注意utf8定义长度超过6的都是不合法的。
public
boolean
utf8Validation(
byte
[] bytes) {
int
expectedLen =
0
;
if
(bytes.length ==
0
) {
return
false
;
}
else
if
((bytes[
0
] & 0b10000000) == 0b00000000) {
expectedLen =
1
;
}
else
if
((bytes[
0
] & 0b11100000) == 0b11000000) {
expectedLen =
2
;
}
else
if
((bytes[
0
] & 0b11110000) == 0b11100000) {
expectedLen =
3
;
}
else
if
((bytes[
0
] & 0b11111000) == 0b11110000) {
expectedLen =
4
;
}
else
if
((bytes[
0
] & 0b11111100) == 0b11111000) {
expectedLen =
5
;
}
else
if
((bytes[
0
] & 0b11111110) == 0b11111100) {
expectedLen =
6
;
}
else
{
return
false
;
}
if
(expectedLen != bytes.length) {
return
false
;
}
for
(
int
i =
1
; i < bytes.length; i++) {
if
((bytes[i] & 0b11000000) != 0b10000000) {
return
false
;
}
}
return
true
;
}