第3章,部分字词修订。

This commit is contained in:
zhliner
2017-08-24 22:26:40 +08:00
parent 9f90d30fa7
commit 725acf091c
10 changed files with 34 additions and 34 deletions

View File

@@ -1,6 +1,6 @@
### 3.5.3. UTF-8
UTF8是一个将Unicode码点编码为字节序列的变长编码。UTF8编码由Go语言之父Ken Thompson和Rob Pike共同发明的现在已经是Unicode的标准。UTF8编码使用1到4个字节来表示每个Unicode码点ASCII部分字符只使用1个字节常用字符部分使用2或3个字节表示。每个符号编码后第一个字节的高端bit位用于表示总共有多少编码个字节。如果第一个字节的高端bit为0则表示对应7bit的ASCII字符ASCII字符每个字符依然是一个字节和传统的ASCII编码兼容。如果第一个字节的高端bit是110则说明需要2个字节后续的每个高端bit都以10开头。更大的Unicode码点也是采用类似的策略处理。
UTF8是一个将Unicode码点编码为字节序列的变长编码。UTF8编码由Go语言之父Ken Thompson和Rob Pike共同发明的现在已经是Unicode的标准。UTF8编码使用1到4个字节来表示每个Unicode码点ASCII部分字符只使用1个字节常用字符部分使用2或3个字节表示。每个符号编码后第一个字节的高端bit位用于表示编码总共有多少个字节。如果第一个字节的高端bit为0则表示对应7bit的ASCII字符ASCII字符每个字符依然是一个字节和传统的ASCII编码兼容。如果第一个字节的高端bit是110则说明需要2个字节后续的每个高端bit都以10开头。更大的Unicode码点也是采用类似的策略处理。
```
0xxxxxxx runes 0-127 (ASCII)
@@ -11,7 +11,7 @@ UTF8是一个将Unicode码点编码为字节序列的变长编码。UTF8编码
变长的编码无法直接通过索引来访问第n个字符但是UTF8编码获得了很多额外的优点。首先UTF8编码比较紧凑完全兼容ASCII码并且可以自动同步它可以通过向前回朔最多2个字节就能确定当前字符编码的开始字节的位置。它也是一个前缀编码所以当从左向右解码时不会有任何歧义也并不需要向前查看译注像GBK之类的编码如果不知道起点位置则可能会出现歧义。没有任何字符的编码是其它字符编码的子串或是其它编码序列的字串因此搜索一个字符时只要搜索它的字节编码序列即可不用担心前后的上下文会对搜索结果产生干扰。同时UTF8编码的顺序和Unicode码点的顺序一致因此可以直接排序UTF8编码序列。同时因为没有嵌入的NUL(0)字节可以很好地兼容那些使用NUL作为字符串结尾的编程语言。
Go语言的源文件采用UTF8编码并且Go语言处理UTF8编码的文本也很出色。unicode包提供了诸多处理rune字符相关功能的函数比如区分字母和数或者是字母的大写和小写转换等unicode/utf8包则提供了用于rune字符序列的UTF8编码和解码的功能。
Go语言的源文件采用UTF8编码并且Go语言处理UTF8编码的文本也很出色。unicode包提供了诸多处理rune字符相关功能的函数比如区分字母和数或者是字母的大写和小写转换等unicode/utf8包则提供了用于rune字符序列的UTF8编码和解码的功能。
有很多Unicode字符很难直接从键盘输入并且还有很多字符有着相似的结构有一些甚至是不可见的字符译注中文和日文就有很多相似但不同的字。Go语言字符串面值中的Unicode转义字符让我们可以通过Unicode码点输入特殊的字符。有两种形式`\uhhhh`对应16bit的码点值`\Uhhhhhhhh`对应32bit的码点值其中h是一个十六进制数字一般很少需要使用32bit的形式。每一个对应码点的UTF8编码。例如下面的字母串面值都表示相同的值
@@ -30,7 +30,7 @@ Unicode转义也可以使用在rune字符中。下面三个字符是等价的
'世' '\u4e16' '\U00004e16'
```
对于小于256码点值可以写在一个十六进制转义字节中例如`\x41`对应字符'A',但是对于更大的码点则必须使用`\u``\U`转义形式。因此,`\xe4\xb8\x96`并不是一个合法的rune字符虽然这三个字节对应一个有效的UTF8编码的码点。
对于小于256码点值可以写在一个十六进制转义字节中,例如`\x41`对应字符'A',但是对于更大的码点则必须使用`\u``\U`转义形式。因此,`\xe4\xb8\x96`并不是一个合法的rune字符虽然这三个字节对应一个有效的UTF8编码的码点。
得益于UTF8编码优良的设计诸多字符串操作都不需要解码操作。我们可以不用解码直接测试一个字符串是否是另一个字符串的前缀
@@ -63,7 +63,7 @@ func Contains(s, substr string) bool {
对于UTF8编码后文本的处理和原始的字节处理逻辑是一样的。但是对应很多其它编码则并不是这样的。上面的函数都来自strings字符串处理包真实的代码包含了一个用哈希技术优化的Contains 实现。)
另一方面如果我们真的关心每个Unicode字符我们可以使用其它处理方式。考虑前面的第一个例子中的字符串混合了中西两种字符。图3.5展示了它的内存表示形式。字符串包含13个字节以UTF8形式编码但是只对应9个Unicode字符
另一方面如果我们真的关心每个Unicode字符我们可以使用其它处理方式。考虑前面的第一个例子中的字符串它混合了中西两种字符。图3.5展示了它的内存表示形式。字符串包含13个字节以UTF8形式编码但是只对应9个Unicode字符
```Go
import "unicode/utf8"
@@ -113,9 +113,9 @@ for range s {
或者我们可以直接调用utf8.RuneCountInString(s)函数。
正如我们前面提到的文本字符串采用UTF8编码只是一种惯例但是对于循环的真正字符串并不是一个惯例这是正确的。如果用于循环的字符串只是一个普通的二进制数据或者是含有错误编码的UTF8数据将会发什么呢?
正如我们前面提到的文本字符串采用UTF8编码只是一种惯例但是对于循环的真正字符串并不是一个惯例这是正确的。如果用于循环的字符串只是一个普通的二进制数据或者是含有错误编码的UTF8数据将会发什么呢?
每一个UTF8字符解码不管是显式地调用utf8.DecodeRuneInString解码或是在range循环中隐式地解码如果遇到一个错误的UTF8编码输入将生成一个特别的Unicode字符`\uFFFD`,在印刷中这个符号通常是一个黑色六角或钻石形状,里面包含一个白色的问号"<EFBFBD>"。当程序遇到这样的一个字符通常是一个危险信号说明输入并不是一个完美没有错误的UTF8字符串。
每一个UTF8字符解码不管是显式地调用utf8.DecodeRuneInString解码或是在range循环中隐式地解码如果遇到一个错误的UTF8编码输入将生成一个特别的Unicode字符`\uFFFD`,在印刷中这个符号通常是一个黑色六角或钻石形状,里面包含一个白色的问号"?"。当程序遇到这样的一个字符通常是一个危险信号说明输入并不是一个完美没有错误的UTF8字符串。
UTF8字符串作为交换格式是非常方便的但是在程序内部采用rune序列可能更方便因为rune大小一致支持数组索引和方便切割。
@@ -147,5 +147,5 @@ fmt.Println(string(0x4eac)) // "京"
如果对应码点的字符是无效的,则用`\uFFFD`无效字符作为替换:
```Go
fmt.Println(string(1234567)) // "<EFBFBD>"
fmt.Println(string(1234567)) // "?"
```