golang中的字符串

0.1、索引https://waterflow.link/articles/1666449874974
1、字符串編碼在go中rune是一個unicode編碼點 。
我們都知道UTF-8將字符編碼為1-4個字節 , 比如我們常用的漢字,UTF-8編碼為3個字節 。所以rune也是int32的別名 。
type rune = int32當我們打印一個英文字符hello的時候,我們可以得到s的長度為5,因為英文字母代表1個字節:
package mainimport "fmt"func main() { s := "hello" fmt.Println(len(s)) // 5}但是當我們打印的時候,會打印3個字節 。因為使用UTF-8,這個字符會被編碼成3個字節:
package mainimport "fmt"func main() { s := "嗨" fmt.Println(len(s)) // 3}所以,我們使用len內置函數輸出的并不是字符數,而是字節數 。
下面看一個有趣的例子,我們都知道漢字符使用3個字節編碼,分別是0xE5, 0x97, 0xA8 。我們運行下面代碼會得到漢字:
package mainimport "fmt"func main() { s := string([]byte{0xE5, 0x97, 0xA8}) fmt.Println(s) // 嗨}所以我們需要知道:

  • 字符集是一組字符,而編碼描述了如何將字符集轉換為二進制
  • 在 Go 中,字符串引用任意字節的不可變切片
  • Go 源碼使用 UTF-8 編碼 。因此,所有字符串文字都是 UTF-8 字符串 。但是因為字符串可以包含任意字節,如果它是從其他地方(不是源碼)獲得的,則不能保證它是基于 UTF-8 編碼的
  • 使用 UTF-8 , 一個 Unicode 字符可以編碼為 1 到 4 個字節
  • 在 Go 中對字符串使用 len 返回字節數,而不是字符數
2、字符串遍歷我們在開發中經常會用到對字符串進行遍歷的場景 。也許我們想對字符串中的每個 rune 執行一個操作 , 或者實現一個自定義函數來搜索特定的子字符串 。在這兩種情況下,我們都必須遍歷字符串的不同字符 。但往往會得到讓我們意想不到的結果 。
我們看下下面的例子,打印一個字符串中的不同字符和對應的位置:
package mainimport "fmt"func main() { s := "h嗨llo" for i := range s {fmt.Printf("字符位置 %d: %c\n", i, s[i]) } fmt.Printf("len=%d\n", len(s))}go run 7.go字符位置 0: h字符位置 1: ?字符位置 4: l字符位置 5: l字符位置 6: olen=7我們想要的效果是通過遍歷字符串 , 打印出每個字符的索引 。但是我們卻得到了一個特殊的字符?,其實我們想要的是 。
但是打印的字節數是符合我們的預期的,因為是一個中文占用了3個字節,所以len返回的是7 。
3、字符串中的字符數如果我們想要正確的獲取字符串的字符數,可以使用go中的utf8包:
package mainimport ( "fmt" "unicode/utf8")func main() { s := "h嗨llo" for i := range s {fmt.Printf("字符位置 %d: %c\n", i, s[i]) } fmt.Printf("len=%d\n", len(s)) fmt.Printf(" rune len=%d\n", utf8.RuneCountInString(s)) // 獲取字符數}go run 7.go字符位置 0: h字符位置 1: ?字符位置 4: l字符位置 5: l字符位置 6: olen=7 rune len=5在這個例子中,可以看到,我們確實遍歷了5次,也就是對應字符串的5個字符 。但是我們獲取到的索引其實是對應每個字符的起始位置 。像下面這樣
golang中的字符串

文章插圖
那我們如何打印出正確的結果呢?我們稍微修改下代碼:
package mainimport ( "fmt" "unicode/utf8")func main() { s := "h嗨llo" for i, v := range s { // 此處改為獲取v , 可以獲取到字符本身fmt.Printf("字符位置 %d: %c\n", i, v) } fmt.Printf("len=%d\n", len(s)) fmt.Printf(" rune len=%d\n", utf8.RuneCountInString(s))}go run 7.go字符位置 0: h字符位置 1: 嗨字符位置 4: l字符位置 5: l字符位置 6: olen=7 rune len=5另外一種方法就是把字符串轉換成rune切片,這樣也會正確打印結果:
package mainimport ( "fmt" "unicode/utf8")func main() { s := "h嗨llo" b := []rune(s) for i := range b {fmt.Printf("字符位置 %d: %c\n", i, b[i]) } fmt.Printf("len=%d\n", len(s)) fmt.Printf(" rune len=%d\n", utf8.RuneCountInString(s))}go run 7.go字符位置 0: h字符位置 1: 嗨字符位置 2: l字符位置 3: l字符位置 4: olen=7 rune len=5下面是rune切片遍歷的過程(中間省略了將字節轉換為rune的過程,需要遍歷字節,復雜度為O(n))
golang中的字符串

文章插圖
4、字符串trim開發中我們經常會遇到去除字符串頭部或者尾部字符的操作 。比如我們現在有個字符串xohelloxo,現在我們想去除尾部的

推薦閱讀