$ cat main.go
package main
import (
"fmt"
"unicode/utf8"
"io/ioutil"
"os"
"log"
)
func main() {
str, err := ioutil.ReadFile(os.Args[1])
if err != nil { log.Fatal(err) }
fmt.Println(utf8.Valid([]byte(str)))
}
$ go run main.go <(echo $'\xed\xa0\xb5')
false
Run Code Online (Sandbox Code Playgroud)
utf8.Valid() 说 '\xed\xa0\xb5' 无效。
\xed: 11101101\xa0: 10100000\xb5: 10110101但是有二进制格式的三个字节。111xxxxx表示它是一个三个字节的字符。根据维基页面上的表格,以下两个字节应该有效。
https://en.wikipedia.org/wiki/UTF-8
有人知道为什么utf8.Valid()将三字节字符显示为无效的 UTF-8 字符吗?
根据维基百科上的代码页布局表,虽然十六进制序列\xed\xa0\xb5遵循 处代码点的编码规则0xd835,但它被认为是无效的,因为它与 UTF-16 中为代理半部分保留的代码点相匹配。查看Unicode的代码点表时,您会看到来自0xD800to的代码点都未0xDFFF分配并标记为“在 UTF-8 中显式无效”。
Unicode 和 ISO/IEC 10646 不会将实际字符分配给 D800–DFFF 范围内的任何代码点——这些代码点仅在用于代理对时才有意义。因此,代理对中的单个代码点不代表字符,除非在代理对中使用,否则无效,并且在 UTF-32 和 UTF-8 中无条件无效(如果应用严格符合标准)。