make loop

This commit is contained in:
chai2010
2015-12-18 14:49:31 +08:00
parent 9fde1ff772
commit f9ac065e47
106 changed files with 725 additions and 725 deletions

View File

@@ -1,7 +1,7 @@
### 3.5.3. UTF-8
UTF8是一个将Unicode码点编码为字节序列的变长编码. UTF8编码由Go言之父 Ken Thompson 和 Rob Pike 共同明, 在已是Unicode的标准. UTF8使用1到4个字节来表示每Unicode码点符号, ASCII部分字符使用1个字节, 常用字符部分使用2或3个字节. 每个符号编码后第一个字节的高端bit位用表示共有多少个字节. 如果第一个字节的高端bit0, 表示对应7bit的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位用表示共有多少個字節. 如果第一個字節的高端bit0, 表示對應7bit的ASCII字符, 每字符一個字節, 和傳統的ASCII編碼兼容. 如果第一個字節的高端bit是110, 則説明需要2個字節; 後續的每高端bit都以10開頭. 更大的Unicode碼點也是采用似的策略理.
```
0xxxxxx runes 0-127 (ASCII)
@@ -10,11 +10,11 @@ UTF8是一个将Unicode码点编码为字节序列的变长编码. UTF8编码由
1110xxx 10xxxxxx 10xxxxxx 10xxxxxx 65536-0x10ffff (other values unused)
```
变长的编码无法直接通索引来访问第n字符, 但是UTF8得了很多外的优点. 首先UTF8编码比较紧凑, 兼容ASCII, 且可以自同步: 它可以通向前朔最多2个字节就能确定当前字符编码的开始字的位置. 它也是一个前缀编码, 所以当从左向右解码时不会有任何歧义也并不需要向前看. 有任何字符的编码是其它字符编码的子串, 或是其它编码序列的字串, 因此索一字符时只要搜索它的字节编码序列可, 不用心前的上下文会对搜索结果产生干扰. 同UTF8编码的顺序和Unicode码点的顺序一致, 因此可以直接排序UTF8编码序列. 同业也没有嵌入的NUL(0)字, 可以很好地兼容那些使用NUL作字符串尾的编程语言.
變長的編碼無法直接通索引來訪問第n字符, 但是UTF8得了很多外的優點. 首先UTF8編碼比較緊湊, 兼容ASCII, 且可以自同步: 它可以通向前朔最多2個字節就能確定當前字符編碼的開始字的位置. 它也是一個前綴編碼, 所以當從左向右解碼時不會有任何歧義也併不需要向前看. 有任何字符的編碼是其它字符編碼的子串, 或是其它編碼序列的字串, 因此索一字符時隻要蒐索它的字節編碼序列可, 不用心前的上下文會對蒐索結果産生榦擾. 同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编码. 例如: 下面的字母串面值都表示相同的值:
有很多Unicode字符很直接從鍵盤輸入, 且很多字符有着相似的結構; 有一些甚至是不可的字符. Go字符串面值中的Unicode轉義字符讓我們可以通Unicode碼點輸入特殊的字符. 有兩種形式, \uhhhh 對應16bit的碼點值, \Uhhhhhhhh 對應32bit的碼點值, 其中h是一十六進製數字; 一般很少需要使用32bit的形式. 每一個對應碼點的UTF8編碼. 例如: 下面的字母串面值都表示相同的值:
```
"世界"
@@ -23,17 +23,17 @@ Go的源文件采用UTF8编码, 并且Go处理UTF8编码的文本也很出色. u
"\U00004e16\U0000754c"
```
上面三个转义序列第一字符串提供替代法, 但是它的值都是相同的.
上面三個轉義序列第一字符串提供替代法, 但是它的值都是相同的.
Unicode转义也可以使用在rune字符中. 下面三字符是等的:
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良的设计, 多字符串操作都不需要解. 我可以不用解直接测试一个字符串是否是另一字符串的前:
得意UTF8良的設計, 多字符串操作都不需要解. 我可以不用解直接測試一個字符串是否是另一字符串的前:
```Go
func HasPrefix(s, prefix string) bool {
@@ -41,7 +41,7 @@ func HasPrefix(s, prefix string) bool {
}
```
或者是后缀测试:
或者是後綴測試:
```Go
func HasSuffix(s, suffix string) bool {
@@ -49,7 +49,7 @@ func HasSuffix(s, suffix string) bool {
}
```
或者是包含子串测试:
或者是包含子串測試:
```Go
func Contains(s, substr string) bool {
@@ -62,9 +62,9 @@ func Contains(s, substr string) bool {
}
```
对于UTF8编码后文本的理和原始的字节处理逻辑一样. 但是对应很多其它编码则并不是这样的. (上面的函数都来自 strings 字符串理包, 然它们的实现包含了一用哈希技术优化的 Contains 实现.)
對於UTF8編碼後文本的理和原始的字節處理邏輯一樣. 但是對應很多其它編碼則併不是這樣的. (上面的函數都來自 strings 字符串理包, 然它們的實現包含了一用哈希技術優化的 Contains 實現.)
另以方面, 如果我们真的关心每Unicode字符, 我可以使用其它机制. 考前面的第一例子中的字符串, 它包混合了中西两种字符. 3.5展示了它的存表示形式. 字符串包含13个字节, 以UTF8形式编码, 但是只对应9个Unicode字符:
另以方面, 如果我們眞的關心每Unicode字符, 我可以使用其它機製. 考前面的第一例子中的字符串, 它包混合了中西兩種字符. 3.5展示了它的存表示形式. 字符串包含13個字節, 以UTF8形式編碼, 但是隻對應9個Unicode字符:
```Go
import "unicode/utf8"
@@ -74,7 +74,7 @@ fmt.Println(len(s)) // "13"
fmt.Println(utf8.RuneCountInString(s)) // "9"
```
为了处理这些真实的字符, 我需要一UTF8解器. unicode/utf8 包提供了实现, 我可以这样使用:
爲了處理這些眞實的字符, 我需要一UTF8解器. unicode/utf8 包提供了實現, 我可以這樣使用:
```Go
for i := 0; i < len(s); {
@@ -84,7 +84,7 @@ for i := 0; i < len(s); {
}
```
每一次用 DecodeRuneInString 函都返回一个 r 和 度, r 对应字符本身, 长度对应r采用UTF8编码后的字节数目. 度可以用更新第i字符在字符串中的字索引位置. 但是这种方式是笨拙的, 我需要更简洁的语法. 幸的是, Go的range循环在处理字符串的候, 会自动隐式解UTF8字符串. 下面的循环运行如3.5所示; 需要意的是对于非ASCII, 索引更新的步长超过1个字节.
每一次調用 DecodeRuneInString 函都返迴一個 r 和 度, r 對應字符本身, 長度對應r采用UTF8編碼後的字節數目. 度可以用更新第i字符在字符串中的字索引位置. 但是這種方式是笨拙的, 我需要更簡潔的語法. 幸的是, Go的range循環在處理字符串的候, 會自動隱式解UTF8字符串. 下面的循環運行如3.5所示; 需要意的是對於非ASCII, 索引更新的步長超過1個字節.
![](../images/ch3-05.png)
@@ -94,7 +94,7 @@ for i, r := range "Hello, 世界" {
}
```
可以使用一个简单的循环来统计字符串中字符的目, 像这样:
可以使用一個簡單的循環來統計字符串中字符的目, 像這樣:
```Go
n := 0
@@ -103,7 +103,7 @@ for _, _ = range s {
}
```
想其它形式的循环那样, 我可以忽略不需要的量:
想其它形式的循環那樣, 我可以忽略不需要的量:
```Go
n := 0
@@ -112,15 +112,15 @@ for range s {
}
```
或者我可以直接用 utf8.RuneCountInString(s) 函.
或者我可以直接調用 utf8.RuneCountInString(s) 函.
正如我前面提到了, 文本字符串采用UTF8编码只是一种惯例,但是对于循环的真正字符串不是一个惯例, 是正的. 如果用于循环的字符串是一普通的二进制数据, 或者是含有错误编码的UTF8数据, 将会发送什?
正如我前面提到了, 文本字符串采用UTF8編碼隻是一種慣例,但是對於循環的眞正字符串不是一個慣例, 是正的. 如果用於循環的字符串是一普通的二進製數據, 或者是含有錯誤編碼的UTF8數據, 將會發送什?
每一UTF8字符解, 不管是示地用 utf8.DecodeRuneInString 解或在 range 循环中隐式地解, 如果遇到一个错误的输入字, 生成一特别的Unicode字符 '\uFFFD', 在印刷中这个符号通常是一黑色六角或石形, 里面包含一白色的问号(?). 程序遇到这样的一字符, 通常是一个信号, 说明输入并不是一完美没有错误的的UTF8编码字符串.
每一UTF8字符解, 不管是示地調用 utf8.DecodeRuneInString 解或在 range 循環中隱式地解, 如果遇到一個錯誤的輸入字, 生成一特别的Unicode字符 '\uFFFD', 在印刷中這個符號通常是一黑色六角或石形, 里面包含一白色的問號(?). 程序遇到這樣的一字符, 通常是一個信號, 説明輸入併不是一完美沒有錯誤的的UTF8編碼字符串.
UTF8作为交换格式是非常方便的, 但是在程序部采用rune型可能更方便, 因rune大小一致, 支持数组索引和方便切割.
UTF8作爲交換格式是非常方便的, 但是在程序部采用rune型可能更方便, 因rune大小一致, 支持數組索引和方便切割.
string 接受到 []rune 的转换, 可以将一个UTF8编码的字符串解码为Unicode字符序列:
string 接受到 []rune 的轉換, 可以將一個UTF8編碼的字符串解碼爲Unicode字符序列:
```Go
// "program" in Japanese katakana
@@ -130,22 +130,22 @@ r := []rune(s)
fmt.Printf("%x\n", r) // "[30d7 30ed 30b0 30e9 30e0]"
```
(在第一Printf中的 `% x` 参数用于在每十六进制数字前插入一空格.)
(在第一Printf中的 `% x` 參數用於在每十六進製數字前插入一空格.)
如果是将一个 []rune 型的Unicode字符切片或数组转为string, 则对它们进行UTF8编码:
如果是將一個 []rune 型的Unicode字符切片或數組轉爲string, 則對它們進行UTF8編碼:
```Go
fmt.Println(string(r)) // "プログラム"
```
将一个整数转型为字符串意思是生成整数作为Unicode码点的UTF8编码的字符串:
將一個整數轉型爲字符串意思是生成整數作爲Unicode碼點的UTF8編碼的字符串:
```Go
fmt.Println(string(65)) // "A", not "65"
fmt.Println(string(0x4eac)) // "京"
```
如果对应码点的字符是效的, 用'\uFFFD'效字符作为替换:
如果對應碼點的字符是效的, 用'\uFFFD'效字符作爲替換:
```Go
fmt.Println(string(1234567)) // "(?)"