Go 字符串
最后修改日期:2025 年 5 月 4 日
在本文中,我们将展示如何在 Golang 中处理字符串。这是 Go 字符串的简单介绍。
定义
Go 中的字符串是不可变的字节序列。与许多将字符串视为字符集合的编程语言不同,Go 字符串本质上是字节切片。在索引字符串时,Go 返回的是字节而不是字符,这意味着多字节字符(例如 UTF-8 编码中的字符)需要特殊处理。
Go 字符串可以存储任意字节,不仅仅是 UTF-8 编码的文本。虽然 Go 的内置字符串操作函数假定为 UTF-8 编码,但字符串本身不强制任何字符编码。这种灵活性允许 Go 字符串表示二进制数据、文件内容或编码文本。
字符串字面量
Go 支持两种字符串字面量:普通字符串和原始字符串。
- 普通字符串:用双引号(
" "
)括起来,它们支持转义序列,例如\n
(换行符)和\t
(制表符)。这些转义序列允许精确地格式化字符串。 - 原始字符串:用反引号(
` `
)括起来,它们会保留其内容,就像编写时一样,不会解释转义序列。这使得它们非常适合存储文件路径、JSON 或多行内容。
由于原始字符串不处理转义序列,因此它们特别适用于处理大型文本块或代码片段,而无需手动转义。
UTF-8 和 Unicode 处理
Go 源文件使用 UTF-8 编码,Go 字符串字面量本质上由 UTF-8 字节序列组成。这些序列映射到Unicode 码点,它们代表单个字符。在 Go 中,Unicode 码点被称为rune,它是 int32
类型的别名。
遍历字符串时,Go 提供了两种主要方法:
- 经典 for 循环:遍历单个字节,这可能无法正确处理多字节字符。
- for-range 循环:解码并处理每个 UTF-8 编码的 rune,确保正确处理多字节字符。
对于-range 循环在处理国际化文本或超出 ASCII 范围的字符时特别有用,因为它能防止多字节序列被意外分割。
字符串操作
Go 通过 strings
包提供了几种内置函数来处理字符串,包括:
strings.Contains(s, substr)
- 检查substr
是否存在于s
中。strings.Split(s, sep)
- 根据sep
将s
分割成子字符串切片。strings.Replace(s, old, new, n)
- 将old
的出现替换为new
。strings.ToUpper(s)
- 将字符串转换为大写。strings.TrimSpace(s)
- 删除开头和结尾的空格。
虽然 Go 中的字符串是不可变的,但您可以使用 bytes.Buffer
类型有效地修改其内容,它允许动态字符串操作,并且性能优于重复连接。
Go 字符串简单示例
以下示例是一个简单的字符串示例。
package main import ( "fmt" ) func main() { w1 := "a red fox" fmt.Println(w1) w2 := w1 + " and a falcon" fmt.Println(w2) }
我们定义一个普通字符串并打印它。然后我们连接两个字符串。
w1 := "a red fox"
普通字符串放在两个双引号字符之间。
w2 := w1 + " and a falcon"
使用 +
运算符,我们将两个字符串相加。
$ go run simple.go a red fox a red fox and a falcon
Go 字符串比较
字符串使用 ==
运算符进行比较。使用 EqualFold
函数进行不区分大小写的比较。
package main import ( "fmt" "strings" ) func main() { w1 := "Aikido" w2 := "aikido" if w1 == w2 { fmt.Println("the strings are equal") } else { fmt.Println("the strings are not equal") } if strings.EqualFold(w1, w2) { fmt.Println("the strings are equal") } else { fmt.Println("the strings are not equal") } }
该示例以区分大小写和不区分大小写的方式比较两个字符串。
$ go run comparing.go the strings are not equal the strings are equal
Go 中的转义序列
转义序列是特殊字符,在字符串字面量中使用时具有特定含义。例如,换行符 \n
转义序列会导致下一个字符出现在新行上。
package main import ( "fmt" ) func main() { w1 := "old falcon\tred fox\nfast dog\tlazy cat\n" fmt.Println(w1) w2 := "it was a \"great film\"" fmt.Println(w2) }
在代码示例中,我们使用了一些转义序列。
w1 := "old falcon\tred fox\nfast dog\tlazy cat\n"
\n
添加换行符,\t
添加水平制表符。
w2 := "it was a \"great film\""
有时我们想打印双引号字符。由于它是 Go 语法的一部分,我们需要使用转义字符来打印它。
$ go run escapes.go old falcon red fox fast dog lazy cat it was a "great film"
Go 原始和多行字符串
原始字符串和多行字符串是用反引号创建的。
package main import ( "fmt" ) func main() { w1 := "old falcon\tred fox\nfast dog\tlazy cat\n" fmt.Println(w1) w2 := `old falcon\tred fox\nfast dog\tlazy cat\n` fmt.Println(w2) sonnet55 := ` Not marble nor the gilded monuments Of princes shall outlive this powerful rhyme, But you shall shine more bright in these contents Than unswept stone besmeared with sluttish time. When wasteful war shall statues overturn, And broils root out the work of masonry, Nor Mars his sword nor war's quick fire shall burn The living record of your memory. 'Gainst death and all-oblivious enmity Shall you pace forth; your praise shall still find room Even in the eyes of all posterity That wear this world out to the ending doom. So, till the Judgement that yourself arise, You live in this, and dwell in lovers' eyes. ` fmt.Println(sonnet55) }
w2
字符串是原始字符串,包含转义字符。它们被打印出来而不是被解释。sonnet55
是 Go 中多行字符串的一个示例。
$ go run raw_multi.go old falcon red fox fast dog lazy cat old falcon\tred fox\nfast dog\tlazy cat\n Not marble nor the gilded monuments Of princes shall outlive this powerful rhyme, But you shall shine more bright in these contents Than unswept stone besmeared with sluttish time. When wasteful war shall statues overturn, And broils root out the work of masonry, Nor Mars his sword nor war's quick fire shall burn The living record of your memory. 'Gainst death and all-oblivious enmity Shall you pace forth; your praise shall still find room Even in the eyes of all posterity That wear this world out to the ending doom. So, till the Judgement that yourself arise, You live in this, and dwell in lovers' eyes.
Go 字符串循环
使用经典的 for 循环,我们遍历字节。for range 循环遍历 rune。
package main import ( "fmt" ) func main() { w := "合気道" for idx, s := range w { fmt.Printf("The index number of %c is %d\n", s, idx) } fmt.Println("Bytes:") for i := 0; i < len(w); i++ { fmt.Printf("%x ", w[i]) } fmt.Println() }
该示例同时使用了两种 for 循环。
$ go run looping.go The index number of 合 is 0 The index number of 気 is 3 The index number of 道 is 6 Bytes: e5 90 88 e6 b0 97 e9 81 93
计数
len
函数计算字节数,而 RuneCountInString
计算字符串中的 rune 数。
package main import ( "fmt" "unicode/utf8" ) func main() { w1 := "Aikido" fmt.Printf(w1 + "\n") fmt.Printf("Number of bytes %d\n", len(w1)) fmt.Printf("Number of runes %d\n", utf8.RuneCountInString(w1)) fmt.Printf("---------------\n") w2 := "合気道" fmt.Printf(w2 + "\n") fmt.Printf("Number of bytes %d\n", len(w2)) fmt.Printf("Number of runes %d\n", utf8.RuneCountInString(w2)) }
该示例打印拉丁字符串和日语假名字符串中的字节数和 rune 数。
$ go run counting.go Aikido Number of bytes 6 Number of runes 6 --------------- 合気道 Number of bytes 9 Number of runes 3
Go 字符串连接/分割
strings.Join
函数将第一个参数的元素连接起来形成一个字符串,而 strings.Split
函数将给定的字符串分割成所有由提供的分隔符分隔的子字符串,并返回一个子字符串切片。
package main import ( "fmt" "strings" ) func main() { langs := []string{"F#", "Go", "Python", "Perl", "Erlang"} s := strings.Join(langs, ", ") fmt.Println(s) data := strings.Split(s, ",") fmt.Println(data) }
我们定义了一个字符串切片。我们使用 strings.Join
将字符串连接成一个字符串,然后使用 strings.Split
将其分割成子字符串。
$ go run join_split.go F#, Go, Python, Perl, Erlang [F# Go Python Perl Erlang]
Go rune
Go rune 是 int32 数据类型的一个别名。它代表一个 Unicode 码点。原始的 rune 这个词属于各种古代日耳曼民族的书面语言,尤其是斯堪的纳维亚人和盎格鲁-撒克逊人。
package main import ( "fmt" ) func main() { data := []rune {'♬', '♛', '♠', '🐘', '🐋'} for i, val := range data { fmt.Printf("Char %c Unicode: %U, Position: %d\n", val, val, i) } }
在代码示例中,我们有一个 rune 数组。这些 rune 是表情符号字符。
for i, val := range data { fmt.Printf("Char %c Unicode: %U, Position: %d\n", val, val, i) }
我们遍历 rune 数组,打印它们以及它们的 Unicode 码点和位置。
$ go run runes.go Char ♬ Unicode: U+266C, Position: 0 Char ♛ Unicode: U+265B, Position: 1 Char ♠ Unicode: U+2660, Position: 2 Char 🐘 Unicode: U+1F418, Position: 3 Char 🐋 Unicode: U+1F40B, Position: 4
来源
The Go Programming Language Specification
在本文中,我们介绍了 Golang 中的字符串。