- Go 入门指南: 字符串
字符串
字符串是 UTF-8 字符的一个序列(当字符为 ASCII 码时则占用 1 个字节,其它字符根据需要占用 2-4 个字节)。UTF-8 是被广泛使用的编码格式,是文本文件的标准编码,其他包括 XML 和 JSON 在内,也都使用该编码。由于该编码对占用字节长度的不定性,Go 中的字符串也可能根据需要占用 1 至 4 个字节,这与其他语言如 C++、Java 或者 Python 不同(Java 始终使用2个字节)。Go 这样做的好处是不仅减少了内存和硬盘空间占用,同时也不用像其他语言那样需要对使用 UTF-8 字符集的文本进行编码和解码。
字符串是一种值类型,且值不可变,即创建某个文本后你无法再次修改这个文本的内容;更深入地讲,字符串是字节的定长数组。
Go 支持一下2种形式的字面值:
解释字符串: 该类字符串使用双引号括起来,其中的相关的转义字符将被替换,这些转义字符包括:
\n
: 换行符\r
: 回车符\t
: tab 键\u
或\U
: Unicode 字符\\
: 反斜杠自身
非解释字符串: 该类字符串使用反引号括起来,支持换行,例如:
1
`This is a raw string \n` 中的 `\n\` 会被原样输出。
和 C/C++ 不一样,Go 中的字符串是根据长度限定,而非特殊字符 \0。string
类型的零值为长度为零的字符串,即空字符串 ""
。
一般的比较运算符(==
、!=
、<
、<=
、>=
、>
)通过在内存中按字节比较来实现字符串的对比。你可以通过函数 len()
来获取字符串所占的字节长度,例如:len(str)
。
字符串的内容(纯字节)可以通过标准索引法来获取,在中括号 [] 内写入索引,索引从 0 开始计数:
- 字符串 str 的第 1 个字节:
str[0]
- 第 i 个字节:
str[i - 1]
- 最后 1 个字节:
str[len(str)-1]
需要注意的是,这种转换方案只对纯 ASCII 码的字符串有效。
注意事项 获取字符串中某个字节的地址的行为是非法的,例如:&str[i]。
字符串拼接符 +
两个字符串 s1 和 s2 可以通过 s := s1 + s2
拼接在一起。s2 追加在 s1 尾部并生成一个新的字符串 s。
你可以通过以下方式来对代码中多行的字符串进行拼接:
1
2str := "Beginning of the string " +
"second part of the string"由于编译器行尾自动补全分号的缘故,加号 + 必须放在第一行。
拼接的简写形式
+=
也可以用于字符串:1
2
3s := "hel" + "lo,"
s += "world!"
fmt.Println(s) //输出 “hello, world!”
在循环中使用加号 +
拼接字符串并不是最高效的做法,更好的办法是使用函数 strings.Join()
,有没有更好地办法了?有!使用字节缓冲(bytes.Buffer
)拼接更加给力。
strings 和 strconv 包
作为一种基本数据结构,每种语言都有一些对于字符串的预定义处理函数。Go 中使用 strings
包来完成对字符串的主要操作。
前缀和后缀
HasPrefix
判断字符串 s 是否以prefix
开头1
strings.HasPrefix(s, prefix string) bool
HasSuffix
判断字符串 s 是否以suffix
结尾1
strings.HasSuffix(s, suffix string) bool
示例 presuffix.go
1
2
3
4
5
6
7
8
9
10
11
12package main
import (
"fmt"
"strings"
)
func main() {
var str string = "This is an example of a string"
fmt.Printf("T/F? Does the string \"%s\" have prefix %s? ", str, "Th")
fmt.Printf("%t\n", strings.HasPrefix(str, "Th"))
}输出:
1
T/F? Does the string "This is an example of a string" have prefix Th? true
字符串包含关系
Contains
判断字符串 s 是否包含substr
1
strings.Contains(s, substr string) bool
判断子字符串或字符在父字符串中出现的位置(索引)
Index
返回子字符串 str 在字符串 s 中的索引(str 的第一个字符的索引),-1 表示字符串 s 不包含字符串 str:1
strings.Index(s, str string) int
LastIndex
返回子字符串 str 在字符串 s 中最后出现位置的索引(str 的第一个字符的索引),-1 表示字符串 s 不包含字符串 str:1
strings.LastIndex(s, str string) int
如果 ch 是非 ASCII 编码的字符,建议使用以下函数来对字符进行定位:
1
strings.IndexRune(s string, r rune) int
示例 index_in_string.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22package main
import (
"fmt"
"strings"
)
func main() {
var str string = "Hi, I'm Marc, Hi."
fmt.Printf("The position of \"Marc\" is: ")
fmt.Printf("%d\n", strings.Index(str, "Marc"))
fmt.Printf("The position of the first instance of \"Hi\" is: ")
fmt.Printf("%d\n", strings.Index(str, "Hi"))
fmt.Printf("The position of the last instance of \"Hi\" is: ")
fmt.Printf("%d\n", strings.LastIndex(str, "Hi"))
fmt.Printf("The position of \"Burger\" is: ")
fmt.Printf("%d\n", strings.Index(str, "Burger"))
}输出
1
2
3
4The position of "Marc" is: 8
The position of the first instance of "Hi" is: 0
The position of the last instance of "Hi" is: 14
The position of "Burger" is: -1
字符串替换
`Replace 用于将字符串 str 中的前 n 个字符串 old 替换为字符串 new,并返回一个新的字符串,如果 n = -1 则替换所有字符串 old 为字符串 new:
1
strings.Replace(str, old, new string, n int) string
统计字符串出现的次数
Count
用于计算字符串 str 在字符串 s 中出现的非重叠次数:1
strings.Count(s, str string) int
示例 count_substring.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17package main
import (
"fmt"
"strings"
)
func main() {
var str string = "Hello, how is it going, Hugo?"
var manyG = "gggggggggg"
fmt.Printf("Number of H's in %s is: ", str)
fmt.Printf("%d\n", strings.Count(str, "H"))
fmt.Printf("Number of double g's in %s is: ", manyG)
fmt.Printf("%d\n", strings.Count(manyG, "gg"))
}输出
1
2Number of H's in Hello, how is it going, Hugo? is: 2
Number of double g’s in gggggggggg is: 5
重复字符串
Repeat
用于重复 count 次字符串 s 并返回一个新的字符串:1
strings.Repeat(s, count int) string
示例 repeat_string.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14package main
import (
"fmt"
"strings"
)
func main() {
var origS string = "Hi there! "
var newS string
newS = strings.Repeat(origS, 3)
fmt.Printf("The new repeated string is: %s\n", newS)
}输出
1
The new repeated string is: Hi there! Hi there! Hi there!
修改字符串大小写
ToLower
将字符串中的 Unicode 字符全部转换为相应的小写字符:1
strings.ToLower(s) string
ToUpper
将字符串中的 Unicode 字符全部转换为相应的大写字符:1
strings.ToUpper(s) string
示例 toupper_lower.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18package main
import (
"fmt"
"strings"
)
func main() {
var orig string = "Hey, how are you George?"
var lower string
var upper string
fmt.Printf("The original string is: %s\n", orig)
lower = strings.ToLower(orig)
fmt.Printf("The lowercase string is: %s\n", lower)
upper = strings.ToUpper(orig)
fmt.Printf("The uppercase string is: %s\n", upper)
}输出
1
2
3The original string is: Hey, how are you George?
The lowercase string is: hey, how are you george?
The uppercase string is: HEY, HOW ARE YOU GEORGE?
修剪字符串
你可以使用 strings.TrimSpace(s)
来剔除字符串开头和结尾的空白符号;
如果你想要剔除指定字符,则可以使用 strings.Trim(s, "cut")
来将开头和结尾的 cut 去除掉。该函数的第二个参数可以包含任何字符;
如果你只想剔除开头或者结尾的字符串,则可以使用 TrimLeft
或者 TrimRight
来实现。
分割字符串
strings.Fields(s)
利用空白作为分隔符将字符串分割为若干块,并返回一个 slice 。如果字符串只包含空白符号,返回一个长度为 0 的 slice 。strings.Split(s, sep)
自定义分割符号对字符串分割,返回 slice 。
因为这 2 个函数都会返回 slice,所以习惯使用 for-range 循环来对其进行处理。
拼接 slice 到字符串
Join
用于将元素类型为 string 的 slice 使用分割符号来拼接组成一个字符串:1
strings.Join(sl []string, sep string) string
示例 strings_splitjoin.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25package main
import (
"fmt"
"strings"
)
func main() {
str := "The quick brown fox jumps over the lazy dog"
sl := strings.Fields(str)
fmt.Printf("Splitted in slice: %v\n", sl)
for _, val := range sl {
fmt.Printf("%s - ", val)
}
fmt.Println()
str2 := "GO1|The ABC of Go|25"
sl2 := strings.Split(str2, "|")
fmt.Printf("Splitted in slice: %v\n", sl2)
for _, val := range sl2 {
fmt.Printf("%s - ", val)
}
fmt.Println()
str3 := strings.Join(sl2,";")
fmt.Printf("sl2 joined by ;: %s\n", str3)
}输出
1
2
3
4
5Splitted in slice: [The quick brown fox jumps over the lazy dog]
The - quick - brown - fox - jumps - over - the - lazy - dog -
Splitted in slice: [GO1 The ABC of Go 25]
GO1 - The ABC of Go - 25 -
sl2 joined by ;: GO1;The ABC of Go;25其它有关字符串操作的文档请参阅 官方文档
从字符串中读取内容
函数 strings.NewReader(str)
用于生成一个 Reader
并读取字符串中的内容,然后返回指向该 Reader
的指针,从其它类型读取内容的函数还有:
Read()
从 [] byte 中读取内容。ReadByte()
和 ReadRune()
从字符串中读取下一个 byte 或者 rune。
字符串与其它类型的转换
与字符串相关的类型转换都是通过 strconv
包实现的。该包包含了一些变量用于获取程序运行的操作系统平台下 int 类型所占的位数,如:strconv.IntSize
。
任何类型 T 转换为字符串总是成功的。针对从数字类型转换到字符串,Go 提供了以下函数:
strconv.Itoa(i int) string
返回数字 i 所表示的字符串类型的十进制数。strconv.FormatFloat(f float64, fmt byte, prec int, bitSize int) string
将 64 位浮点型的数字转换为字符串,其中fmt
表示格式(其值可以是 ‘b’、’e’、’f’ 或 ‘g’),prec
表示精度,bitSize
则使用 32 表示 float32,用 64 表示 float64。
利用多返回值的特性,这些函数会返回 2 个值,第 1 个是转换后的结果(如果转换成功),第 2 个是可能出现的错误,因此,我们一般使用以下形式来进行从字符串到其它类型的转换:
1 | val, err = strconv.Atoi(s) |
在下面这个示例中,我们忽略可能出现的转换错误:string_conversion.go
1 | package main |
输出
1 | 64 位系统: |
更多有关该包的讨论,请参阅 官方文档