1. 程式人生 > 其它 >Go 中的 byte、rune 與 string

Go 中的 byte、rune 與 string

byte 和 rune

byte 是 uint8 的別名,其字面量是 8 位整數值,byte 切片相比於不可變的 string 方便常用許多。它可以更改每個位元組或字元。這對於處理檔案內容(無論是文字檔案、二進位制檔案還是來自網路的I/O流)非常有效。byte 切片是一個可變的位元組序列

rune 是 int32 的別名,其字面量是 32 位整數值,用來表示 Unicode 字元編碼。rune 類似於 byte,不同點在於 rune 每個索引是一個字元而不是一個位元組。rune 切片是對位元組片的重新分組使得每個索引都是一個字元。

如果你處理的文字檔案有很多非 ascii 字元,比如中文文字、數學公式或帶有表情符號的文字,使用 rune 是最好的。

rune 也是從字串中獲取子字串的理想選擇。它支援 Unicode 字元,沒有資料損壞的風險。

對於 []rune,len()和索引都是基於 rune(int32)的。
當你將 []rune 轉換為 string 時,每個 rune 成為字串中的一個 utf-8 字元。

byte 和 rune 的區別

func main() {
	s := "GÖ"
	sample := "H哈"

	sByte := []byte(s)
	sRune := []rune(s)
	sampleByte := []byte(sample)
	sampleRune := []rune(sample)

	fmt.Printf("%s\nsByte: %d\nsRune: %d\n", s, sByte, sRune)
	fmt.Println("------")
	fmt.Printf("%s\nsampleByte: %d\nsampleRune: %d\n", sample, sampleByte, sampleRune)
}

可以看到rune 中非 ASCII 碼字元的 Unicode 編碼為 1-3 位元組,與 ASCII 碼字元的位元組數不一定相同。

string

string 是不可變的 byte 切片。因為Go中的原始碼使用 utf-8 編碼,因此每個字串也使用utf-8編碼,即 string 字面量是 utf-8 編碼,以 byte 為單位的。string 中的每個字元實際佔用 1-3 個位元組,而每個 rune 佔 4 個位元組。

  • 使用 rune() 可把 byte 為單位的字元轉換為 rune 字元,對於 ASCII 字元來說,rune 值和 byte 值相同,而對於 Unicode 編碼的字元來說便不同了。
  • 使用 []rune() 將 string 轉換 rune 陣列。當將字串轉換為 rune 切片時,字串中的每個 utf-8 字元被轉換為一個 rune,從而獲得包含字串 Unicode 編碼字元的新切片。
  • 對於 string,len()和索引都是基於 byte(unint8)的
  • 在 Go 中將字串轉換為 rune 切片是一個標準操作,沒有資料損壞的風險。
    字串是處理短位元組或字元序列比較好的方法。每次對字串進行操作(例如查詢替換字串或接受子字串)時,都會建立一個新的字串。如果字串非常大,例如檔案內容,則效率非常低。

string 中索引字元

例如我們先看下面程式:

func main() {

	sample := "Hel哈"
	for i := 0; i < len(sample); i++ {
		fmt.Print(sample[i], " ")
	}
	fmt.Println()
	fmt.Printf("%s\t的位元組長度: %d\n", sample, len(sample))
	fmt.Printf("哈\t字元的位元組長度: %d\n", utf8.RuneLen('哈'))
	fmt.Printf("%s\t的字元長度: %d\n", sample, utf8.RuneCountInString(sample))
}

輸出:

72 101 108 229 147 136 
Hel哈   的位元組長度: 6
哈      字元的位元組長度: 3
Hel哈   的字元長度: 4

可以看出字串的長度(len)和字串的字元長度(RuneCountInString)是不同的。因為字串是位元組切片,Go 預設 UTF-8,儲存非 ASCII 字元時,每個字元則會儲存 1-3 個位元組。所以想要正確地索引字串中的字元有以下兩種方法:

  1. 將字串轉換為 rune 切片
  2. 使用 range 操作符迭代 Unicode 字元
    也就是說對字串進行 rang 迭代,是字元迭代,而不是位元組迭代。

關於編碼的一些方法

utf8.ValidRune(chr) 判斷 chr 是否可以編碼為合法的utf-8序列。
utf8.RuneLen(chr) 檢視字元 chr 的位元組長度
utf8.RuneCount() 檢視位元組陣列中按照 rune 單位的字元長度
utf8.RuneCountInString 檢視字串按照 rune 單位的長度

參考資料

  1. Golang: How To Convert String To Rune in Go Example
  2. go - What is a rune? - Stack Overflow