mirror of
https://github.com/gopl-zh/gopl-zh.github.com.git
synced 2024-12-01 02:28:56 +00:00
ch3-05 review
This commit is contained in:
parent
33480e55d6
commit
315fb47435
@ -1,8 +1,8 @@
|
||||
### 3.5.2. Unicode
|
||||
|
||||
在很久以前,世界还是比較簡單的,起碼計算機世界就隻有一個ASCII字符集:美国信息交換標準代碼。ASCII,更準確地説是美国的ASCII,使用7bit來表示128個字符:包含英文字母的大小寫、數字、各種標點符號和設置控製符。對於早期的計算機程序来说,這些就足夠了,但是這也導致了世界上很多其他地區的用戶無法直接使用自己的符号繫統。隨着互聯網的發展,混合多種語言的數據變得很常見(译注:比如本身的英文原文或中文翻译都包含了ASCII、中文、日文等多种语言字符)。如何有效處理這些包含了各種語言的豐富多樣的文本數據呢?
|
||||
在很久以前,世界還是比較簡單的,起碼計算機世界就隻有一個ASCII字符集:美国信息交換標準代碼。ASCII,更準確地説是美国的ASCII,使用7bit來表示128個字符:包含英文字母的大小寫、數字、各種標點符號和設置控製符。對於早期的計算機程序來説,這些就足夠了,但是這也導致了世界上很多其他地區的用戶無法直接使用自己的符號繫統。隨着互聯網的發展,混合多種語言的數據變得很常見(譯註:比如本身的英文原文或中文翻譯都包含了ASCII、中文、日文等多種語言字符)。如何有效處理這些包含了各種語言的豐富多樣的文本數據呢?
|
||||
|
||||
答案就是使用Unicode( http://unicode.org ),它收集了這個世界上所有的符号繫統,包括重音符號和其它變音符號,製表符和迴車符,還有很多神祕的符號,每個符號都分配一個唯一的Unicode碼點,Unicode碼點對應Go語言中的rune整数類型(译注:rune是int32等价类型)。
|
||||
答案就是使用Unicode( http://unicode.org ),它收集了這個世界上所有的符號繫統,包括重音符號和其它變音符號,製表符和迴車符,還有很多神祕的符號,每個符號都分配一個唯一的Unicode碼點,Unicode碼點對應Go語言中的rune整數類型(譯註:rune是int32等價類型)。
|
||||
|
||||
在第八版本的Unicode標準收集了超過120,000個字符,涵蓋超過100多種語言。這些在計算機程序和數據中是如何體現的呢?通用的表示一個Unicode碼點的數據類型是int32,也就是Go語言中rune對應的類型;它的同義詞rune符文正是這個意思。
|
||||
|
||||
|
@ -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)
|
||||
@ -9,11 +9,11 @@ UTF8是一個將Unicode碼點編碼爲字節序列的變長編碼。UTF8編碼
|
||||
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 65536-0x10ffff (other values unused)
|
||||
```
|
||||
|
||||
變長的編碼無法直接通過索引來訪問第n個字符,但是UTF8编码穫得了很多額外的優點。首先UTF8編碼比較緊湊,完全兼容ASCII码,併且可以自動同步:它可以通過向前迴朔最多2個字節就能確定當前字符編碼的開始字節的位置。它也是一個前綴編碼,所以當從左向右解碼時不會有任何歧義也併不需要向前査看(译注:像GBK之类的编码,如果不知道起点位置则可能会出现歧义)。沒有任何字符的編碼是其它字符編碼的子串,或是其它編碼序列的字串,因此蒐索一個字符時隻要蒐索它的字節編碼序列卽可,不用擔心前後的上下文會對蒐索結果産生榦擾。同時UTF8編碼的順序和Unicode碼點的順序一致,因此可以直接排序UTF8編碼序列。同时因为沒有嵌入的NUL(0)字節,可以很好地兼容那些使用NUL作爲字符串結尾的編程語言。
|
||||
變長的編碼無法直接通過索引來訪問第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編碼。例如:下面的字母串面值都表示相同的值:
|
||||
有很多Unicode字符很難直接從鍵盤輸入,併且還有很多字符有着相似的結構;有一些甚至是不可見的字符(譯註:中文和日文就有很多相似但不同的字)。Go語言字符串面值中的Unicode轉義字符讓我們可以通過Unicode碼點輸入特殊的字符。有兩種形式:\uhhhh對應16bit的碼點值,\Uhhhhhhhh對應32bit的碼點值,其中h是一個十六進製數字;一般很少需要使用32bit的形式。每一個對應碼點的UTF8編碼。例如:下面的字母串面值都表示相同的值:
|
||||
|
||||
```
|
||||
"世界"
|
||||
@ -32,7 +32,7 @@ Unicode轉義也可以使用在rune字符中。下面三個字符是等價的:
|
||||
|
||||
對於小於256碼點值可以寫在一個十六進製轉義字節中,例如'\x41'對應字符'A',但是對於更大的碼點則必鬚使用\u或\U轉義形式。因此,'\xe4\xb8\x96'併不是一個合法的rune字符,雖然這三個字節對應一個有效的UTF8編碼的碼點。
|
||||
|
||||
得益於UTF8编码優良的設計,諸多字符串操作都不需要解碼操作。我們可以不用解碼直接測試一個字符串是否是另一個字符串的前綴:
|
||||
得益於UTF8編碼優良的設計,諸多字符串操作都不需要解碼操作。我們可以不用解碼直接測試一個字符串是否是另一個字符串的前綴:
|
||||
|
||||
```Go
|
||||
func HasPrefix(s, prefix string) bool {
|
||||
@ -61,9 +61,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"
|
||||
@ -73,7 +73,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); {
|
||||
@ -83,7 +83,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)
|
||||
|
||||
@ -115,11 +115,11 @@ for range s {
|
||||
|
||||
正如我們前面提到的,文本字符串采用UTF8編碼隻是一種慣例,但是對於循環的眞正字符串併不是一個慣例,這是正確的。如果用於循環的字符串隻是一個普通的二進製數據,或者是含有錯誤編碼的UTF8數據,將會發送什麽呢?
|
||||
|
||||
每一個UTF8字符解碼,不管是顯式地調用utf8.DecodeRuneInString解碼或是在range循環中隱式地解碼,如果遇到一個錯誤的UTF8编码輸入,將生成一個特别的Unicode字符'\uFFFD',在印刷中這個符號通常是一個黑色六角或鑽石形狀,里面包含一個白色的問號(?)。當程序遇到這樣的一個字符,通常是一個危险信號,説明輸入併不是一個完美沒有錯誤的UTF8字符串。
|
||||
每一個UTF8字符解碼,不管是顯式地調用utf8.DecodeRuneInString解碼或是在range循環中隱式地解碼,如果遇到一個錯誤的UTF8編碼輸入,將生成一個特别的Unicode字符'\uFFFD',在印刷中這個符號通常是一個黑色六角或鑽石形狀,里面包含一個白色的問號(?)。當程序遇到這樣的一個字符,通常是一個危險信號,説明輸入併不是一個完美沒有錯誤的UTF8字符串。
|
||||
|
||||
UTF8字符串作爲交換格式是非常方便的,但是在程序內部采用rune序列可能更方便,因爲rune大小一致,支持數組索引和方便切割。
|
||||
|
||||
string接受到[]rune的类型轉換,可以將一個UTF8編碼的字符串解碼爲Unicode字符序列:
|
||||
string接受到[]rune的類型轉換,可以將一個UTF8編碼的字符串解碼爲Unicode字符序列:
|
||||
|
||||
```Go
|
||||
// "program" in Japanese katakana
|
||||
@ -137,7 +137,7 @@ fmt.Printf("%x\n", r) // "[30d7 30ed 30b0 30e9 30e0]"
|
||||
fmt.Println(string(r)) // "プログラム"
|
||||
```
|
||||
|
||||
將一個整數轉型爲字符串意思是生成以只包含对应Unicode碼點字符的UTF8字符串:
|
||||
將一個整數轉型爲字符串意思是生成以隻包含對應Unicode碼點字符的UTF8字符串:
|
||||
|
||||
```Go
|
||||
fmt.Println(string(65)) // "A", not "65"
|
||||
|
@ -2,13 +2,13 @@
|
||||
|
||||
標準庫中有四個包對字符串處理尤爲重要:bytes、strings、strconv和unicode包。strings包提供了許多如字符串的査詢、替換、比較、截斷、拆分和合併等功能。
|
||||
|
||||
bytes包也提供了很多類似功能的函數,但是針對和字符串有着相同結構的[]byte類型。因爲字符串是隻讀的,因此逐步構建字符串會導致很多分配和複製。在這種情況下,使用bytes.Buffer類型将會更有效,稍後我們將展示。
|
||||
bytes包也提供了很多類似功能的函數,但是針對和字符串有着相同結構的[]byte類型。因爲字符串是隻讀的,因此逐步構建字符串會導致很多分配和複製。在這種情況下,使用bytes.Buffer類型將會更有效,稍後我們將展示。
|
||||
|
||||
strconv包提供了布爾型、整型數、浮點數和對應字符串間的相互轉換, 還提供了雙引號的字符串面值形式的轉換.
|
||||
strconv包提供了布爾型、整型數、浮點數和對應字符串的相互轉換,還提供了雙引號轉義相關的轉換。
|
||||
|
||||
unicode 包提供了類似 IsDigit, IsLetter, IsUpper, 和 IsLower 等功能, 它們用於給字符分類. 每個函數有一個單一的rune類型的參數, 然後返迴一個布爾值. 像 ToUpper 和 ToLower 之類的轉換函數將用於rune字符的大小寫轉換. 所有的這些函數都是遵循Unicode標準定義的字母,數字等分類規范. strings 包也有類似的函數, 它們是 ToUpper 和 ToLower, 將原始字符串的每個字符都做相應的轉換, 然後返迴新的字符串.
|
||||
unicode包提供了IsDigit、IsLetter、IsUpper和IsLower等類似功能,它們用於給字符分類。每個函數有一個單一的rune類型的參數,然後返迴一個布爾值。而像ToUpper和ToLower之類的轉換函數將用於rune字符的大小寫轉換。所有的這些函數都是遵循Unicode標準定義的字母、數字等分類規范。strings包也有類似的函數,它們是ToUpper和ToLower,將原始字符串的每個字符都做相應的轉換,然後返迴新的字符串。
|
||||
|
||||
下面的 basename 函數的靈感由Unix shell的同名工具而來. 在我們實現的版本中, basename(s) 將看起來像是繫統路徑的前綴刪除, 同時將看似文件類型的後綴名刪除:
|
||||
下面例子的basename函數靈感於Unix shell的同名工具。在我們實現的版本中,basename(s)將看起來像是繫統路徑的前綴刪除,同時將看似文件類型的後綴名部分刪除:
|
||||
|
||||
```Go
|
||||
fmt.Println(basename("a/b/c.go")) // "c"
|
||||
@ -16,7 +16,7 @@ fmt.Println(basename("c.d.go")) // "c.d"
|
||||
fmt.Println(basename("abc")) // "abc"
|
||||
```
|
||||
|
||||
第一個版本併沒有使用任何庫, 全部手工實現:
|
||||
第一個版本併沒有使用任何庫,全部手工硬編碼實現:
|
||||
|
||||
```Go
|
||||
gopl.io/ch3/basename1
|
||||
@ -41,7 +41,7 @@ func basename(s string) string {
|
||||
}
|
||||
```
|
||||
|
||||
一個簡化的版本使用了 strings.LastIndex 庫函數:
|
||||
簡化個版本使用了strings.LastIndex庫函數:
|
||||
|
||||
```Go
|
||||
gopl.io/ch3/basename2
|
||||
@ -56,10 +56,9 @@ func basename(s string) string {
|
||||
}
|
||||
```
|
||||
|
||||
path 和 path/filepath 包提供了關於文件名更一般的函數操作. 使用斜槓分隔路徑可以在任何操作繫統上工作. 斜槓本身不應該用於文件名, 但是在其他一些領域可能是有效的, 例如URL路徑組件. 相比之下, path/filepath 包使用操作繫統本身的路徑規則, 例如 POSIX 繫統使用 /foo/bar, Microsoft Windows 使用 c:\foo\bar 等.
|
||||
path和path/filepath包提供了關於文件路徑名更一般的函數操作。使用斜槓分隔路徑可以在任何操作繫統上工作。斜槓本身不應該用於文件名,但是在其他一些領域可能會用於文件名,例如URL路徑組件。相比之下,path/filepath包則使用操作繫統本身的路徑規則,例如POSIX繫統使用/foo/bar,而Microsoft Windows使用c:\foo\bar等。
|
||||
|
||||
|
||||
讓我們繼續另一個字符串的例子. 任務是將一個表示整值的字符串, 每隔三個字符插入一個逗號, 例如 "12345" 處理後成爲 "12,345". 這個版本隻適用於整數類型; 支持浮點數類型的支持留做練習.
|
||||
讓我們繼續另一個字符串的例子。函數的功能是將一個表示整值的字符串,每隔三個字符插入一個逗號分隔符,例如“12345”處理後成爲“12,345”。這個版本隻適用於整數類型;支持浮點數類型的支持留作練習。
|
||||
|
||||
```Go
|
||||
gopl.io/ch3/comma
|
||||
@ -74,11 +73,11 @@ func comma(s string) string {
|
||||
}
|
||||
```
|
||||
|
||||
輸入 comma 的參數是一個字符串. 如果輸入字符串的長度小於或等於3的話, 則不需要插入逗號. 否則, comma 將在最後三個字符前切割爲兩個兩個子串, 然後用前面的子串遞歸調用自身.
|
||||
輸入comma函數的參數是一個字符串。如果輸入字符串的長度小於或等於3的話,則不需要插入逗分隔符。否則,comma函數將在最後三個字符前位置將字符串切割爲兩個兩個子串併插入逗號分隔符,然後通過遞歸調用自身來出前面的子串。
|
||||
|
||||
一個字符串包含的字節數組, 一旦創建, 是不可變的. 相比之下, 一個字節切片的原始則可以自由地脩改.
|
||||
一個字符串是包含的隻讀字節數組,一旦創建,是不可變的。相比之下,一個字節slice的元素則可以自由地脩改。
|
||||
|
||||
字符串和字節切片可以相互轉換:
|
||||
字符串和字節slice之間可以相互轉換:
|
||||
|
||||
```Go
|
||||
s := "abc"
|
||||
@ -86,9 +85,9 @@ b := []byte(s)
|
||||
s2 := string(b)
|
||||
```
|
||||
|
||||
從概念上講, []byte(s) 轉換是分配了一個新的字節數組保存了字符串數據的拷貝, 然後引用這個字節數組. 編譯器的優化可以避免在一些場景下分配和複製字符串數據, 但總的來説需要確保在b被脩改的情況下, 原始的s字符串也不會改變. 將一個字節切片轉到字符串的 string(b) 操作則是構造一個拷貝, 以確保s2字符串是隻讀的.
|
||||
從概念上講,一個[]byte(s)轉換是分配了一個新的字節數組用於保存字符串數據的拷貝,然後引用這個底層的字節數組。編譯器的優化可以避免在一些場景下分配和複製字符串數據,但總的來説需要確保在變量b被脩改的情況下,原始的s字符串也不會改變。將一個字節slice轉到字符串的string(b)操作則是構造一個字符串拷貝,以確保s2字符串是隻讀的。
|
||||
|
||||
爲了避免轉換中不必要的內存分配, bytes包和strings同時提供了許多類似的實用函數. 下面是strings包中的六個函數:
|
||||
爲了避免轉換中不必要的內存分配,bytes包和strings同時提供了許多實用函數。下面是strings包中的六個函數:
|
||||
|
||||
```Go
|
||||
func Contains(s, substr string) bool
|
||||
@ -99,7 +98,7 @@ func Index(s, sep string) int
|
||||
func Join(a []string, sep string) string
|
||||
```
|
||||
|
||||
bytes 包中對應的六個函數:
|
||||
bytes包中也對應的六個函數:
|
||||
|
||||
```Go
|
||||
func Contains(b, subslice []byte) bool
|
||||
@ -110,9 +109,9 @@ func Index(s, sep []byte) int
|
||||
func Join(s [][]byte, sep []byte) []byte
|
||||
```
|
||||
|
||||
唯一的區别是字符串類型參數被替換成了字節切片類型的參數.
|
||||
它們之間唯一的區别是字符串類型參數被替換成了字節slice類型的參數。
|
||||
|
||||
bytes 包還提供了 Buffer 類型用於字節切片的緩存. 一個 Buffer 開始是空的, 但是隨着 string, byte, 和 []byte 等類型數據的寫入可以動態增長, 一個 bytes.Buffer 變量併不需要處理化, 因此零值也是有效的:
|
||||
bytes包還提供了Buffer類型用於字節slice的緩存。一個Buffer開始是空的,但是隨着string、byte或[]byte等類型數據的寫入可以動態增長,一個bytes.Buffer變量併不需要處理化,因爲零值也是有效的:
|
||||
|
||||
```Go
|
||||
gopl.io/ch3/printints
|
||||
@ -136,16 +135,15 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
當向 bytes.Buffer 添加任意字符的UTF8編碼, 最好使用 bytes.Buffer 的 WriteRune 方法, 但是 WriteByte 方法對於寫入類似 '[' 和 ']' 等 ASCII 字符則更有效.
|
||||
當向bytes.Buffer添加任意字符的UTF8編碼時,最好使用bytes.Buffer的WriteRune方法,但是WriteByte方法對於寫入類似'['和']'等ASCII字符則會更加有效。
|
||||
|
||||
bytes.Buffer 類型有着諸多實用的功能, 我們在第七章討論接口時層涉及到, 我們將看看如何將它用作一個I/O 的輸入和輸出對象, 例如 Fprintf 的 io.Writer 輸出, 或作爲輸入源 io.Reader.
|
||||
bytes.Buffer類型有着很多實用的功能,我們在第七章討論接口時將會涉及到,我們將看看如何將它用作一個I/O的輸入和輸出對象,例如當做Fprintf的io.Writer輸出對象,或者當作io.Reader類型的輸入源對象。
|
||||
|
||||
**練習3.10:** 編寫一個非遞歸版本的comma函數, 使用 bytes.Buffer 代替字符串鏈接操作.
|
||||
**練習 3.10:** 編寫一個非遞歸版本的comma函數,使用bytes.Buffer代替字符串鏈接操作。
|
||||
|
||||
**練習3.11:** 完善 comma 函數, 以支持浮點數處理和一個可選的正負號處理.
|
||||
**練習 3.11:** 完善comma函數,以支持浮點數處理和一個可選的正負號的處理。
|
||||
|
||||
|
||||
**練習3.12:** 編寫一個函數, 判斷兩個字符串是否是是相互打亂的, 也就是説它們有着相同的字符, 但是對應不同的順序.
|
||||
**練習 3.12:** 編寫一個函數,判斷兩個字符串是否是是相互打亂的,也就是説它們有着相同的字符,但是對應不同的順序。
|
||||
|
||||
|
||||
|
||||
|
@ -1,9 +1,8 @@
|
||||
### 3.5.5. 字符串和數字的轉換
|
||||
|
||||
除了字符串、字符、字節之間的轉換,字符串和數值之間的轉換也比較常見。由strconv包提供這類轉換功能。
|
||||
|
||||
除了字符串, 字符, 字節 之間的轉換, 字符串和數值之間的轉換也比較常見. 由 strconv 包提供這類轉換功能.
|
||||
|
||||
將一個整數轉爲字符串, 一種方法是用 fmt.Sprintf; 另一個方法是用 strconv.Itoa(“整數到ASCII”):
|
||||
將一個整數轉爲字符串,一種方法是用fmt.Sprintf返迴一個格式化的字符串;另一個方法是用strconv.Itoa(“整數到ASCII”):
|
||||
|
||||
```Go
|
||||
x := 123
|
||||
@ -11,28 +10,28 @@ y := fmt.Sprintf("%d", x)
|
||||
fmt.Println(y, strconv.Itoa(x)) // "123 123"
|
||||
```
|
||||
|
||||
FormatInt和FormatUint可以用不同的進製來格式化數字:
|
||||
FormatInt和FormatUint函數可以用不同的進製來格式化數字:
|
||||
|
||||
```Go
|
||||
fmt.Println(strconv.FormatInt(int64(x), 2)) // "1111011"
|
||||
```
|
||||
|
||||
fmt.Printf 函數的 %b, %d, %u, 和 %x 等參數提供功能往往比strconv 包的 Format 函數方便很多, 特别是在需要包含附加信息的時候:
|
||||
fmt.Printf函數的%b、%d、%u和%x等參數提供功能往往比strconv包的Format函數方便很多,特别是在需要包含附加額外信息的時候:
|
||||
|
||||
```Go
|
||||
s := fmt.Sprintf("x=%b", x) // "x=1111011"
|
||||
```
|
||||
|
||||
如果要將一個字符串解析爲整數, 可以使用 strconv 包的 Atoi 或 ParseInt 函數, 還有用於解析無符號整數的 ParseUint 函數:
|
||||
如果要將一個字符串解析爲整數,可以使用strconv包的Atoi或ParseInt函數,還有用於解析無符號整數的ParseUint函數:
|
||||
|
||||
```Go
|
||||
x, err := strconv.Atoi("123") // x is an int
|
||||
y, err := strconv.ParseInt("123", 10, 64) // base 10, up to 64 bits
|
||||
```
|
||||
|
||||
ParseInt 函數的第三個參數是用於指定整型數的大小; 例如16表示int16, 0則表示int. 在任何情況下, 返迴的結果 y 總是 int64 類型, 你可以通過強製類型轉換將它轉爲更小的整數類型.
|
||||
ParseInt函數的第三個參數是用於指定整型數的大小;例如16表示int16,0則表示int。在任何情況下,返迴的結果y總是int64類型,你可以通過強製類型轉換將它轉爲更小的整數類型。
|
||||
|
||||
有時候也會使用 fmt.Scanf 來解析輸入的字符串和數字, 特别是當字符串和數字混合在一行的時候, 它可以靈活處理不完整或不規則的輸入.
|
||||
有時候也會使用fmt.Scanf來解析輸入的字符串和數字,特别是當字符串和數字混合在一行的時候,它可以靈活處理不完整或不規則的輸入。
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user