[Go 入门] 第八章 使用字符串

Go 入门系列参考于互联网资料与 人民邮电出版社 《Go 语言入门经典》 与 《Effective Go》,编写目的在于学习交流,如有侵权,请联系删除

字符串是基本的编程构件, 本文内容:

创建字符串字面量

Go语言支持两种创建字符串字面量的方式。解释型字符串字面量是用双引号括起的字符,如"hello"。一种创建字符串的简单方式是使用解释型字符串字面量

1
2
3
4
func main() {
s := "I am an interpreted string literal"
fmt.Println(s)
}

除换行符和未转移的双引号外,解释型字符串字面量可包含其他任何字符。对于前面有反斜杠(\)的字符,将像它们出现在 rune 字面量中那样进行解读

下面是单字符转义序列对应的 Unicode 字符:

rune 字面量 Unicode 字符
\a U+0007 (警告声蜂鸣)
\b U+0008 (退格)
\f U+000C (换页符)
\n U+000A (换行符)
\r U+000D (回车)
\t U+0009 (水平制表符)
\v U+000b (垂直制表符)
\ U+005c (反斜杆)
\’ U+0027 (单引号,这个转义序列只能包含在 rune 字面量中)
\“ U+0022 (双引号,这个转义序列只能包含在字符串字面量中)

理解 rune 字面量

使用 rune 字面量,可将解释型字符串字面量分成多行,还可在其中包含制表符和其他格式选项。

1
2
3
4
func main() {
s := "After a backslash, certain single character escapes represent special values\nn is a line feed or new line \n\t t is tab"
fmt.Println(s)
}

上述的输出为:

1
2
3
After a backslash, certain single character escapes represent special values
n is a line feed or new line
t is tab

原始字符串字面量用单引号括起,如`hello`。不同于解释型字符串,原始字符串中的反斜杆没有特殊含义,Go 按原样解释这种字符。通过使用原始字符串字面量,无需利用反斜杠就能生成前一个示例那样的输出

1
2
3
4
5
6
func main() {
s := `After a backslash, certain single character escapes represent special values
n is a line feed or new line
t is tab`
fmt.Println(s)
}

拼接字符串

Go 语言中,要拼接(合并)字符串,可将运算符 + 用于字符串变量。字符串是使用解释型字符串字面量还是原始字符串字面量创建的无关紧要。运算符 + 将它左边和右边的字符串合并成一个字符串

1
2
3
4
func main() {
s := "Oh sweet ignition" + " be my fuse"
fmt.Println(s)
}

还可以使用复合赋值运算符 += 来拼接字符串,这个运算符将它右边的字符串合并到左边的字符串中。可在循环中反复这样来生成字符串

1
2
3
4
func main() {
s := "Can you hear me?"
s += "\nHear me screamin?"
}

只能拼接类型为字符串的变量,如果将整数和字符串进行拼接将导致编译错误,如果需要将其他类型转换成字符串,Go 标准库提供了 strconv 包,可以使用其中的 Itoa 将整数转换成字符串

1
2
3
4
5
6
7
func main() {
var i = 1
var s = " egg"
intToString := strconv.Itoa(i)
var breakfast = intToString + s
fmt.Println(breakfast)
}

使用缓冲区拼接字符串

对于简单而少量的拼接,使用运算符 + 和复合运算符 += 的效果虽然很好,但随着拼接操作次数的增加,效率并不高。如果需要在循环中拼接字符串,则使用空的字符缓冲区来拼接的效率更高

1
2
3
4
5
6
7
func main() {
var buffer bytes.Buffer
for i := 0; i < 500; i++ {
buffer.WriteString("z")
}
fmt.Println(buffer.String())
}

理解字符串是什么

要理解字符串是什么,就必须明白计算机是如何显示和储存字符的。计算机将数据解读为数字。历史上有很多编码标准,最后大家就如何将字符映射到数字达成了一致。ASCII(美国信息交换标准码)曾经是最重要的编码标准,它就如何使用数字来表达英语字母中的字符进行了标准化。

ASCII 编码标准定义了如何使用7位的整数来表示128个字符。

ASCII中的一些字符:

二进制 八进制 十进制 十六进制 字符
1000001 101 65 41 A
1000010 102 66 42 B
1110100 164 116 74 t

虽然 ASCII 在英语字符标准化的道路上迈出了重要的一步,但它不包含其他任何语言的字符集,也就是只能用英语说 hello,但不能用中文说 你好

鉴于此,Unicode编码方案于1987年应运而生,它支持全球各地的大多数字符集。最新的版本支持128000个字符,涵盖135种或现代或古老的语言。更重要的是,Unicode涵盖了ASCII标准,其开头的128个字符就是ASCII字符。

很多字符编码方案实现了Unicode标准,其中最著名的就是 UTF-8。Go语言的两位设计者 Rob PikeKen Thompson也是UTF-8的联合设计者。

要更深入的理解字符串以及如何操作它们,必须首先知道 Go 语言中的字符串实际上是只读的字节切片。要获悉字符串包含多少个字节,可使用 Go 语言的内置函数 len

1
2
3
4
s := "hello"
fmt.Println(len(s))

//outputs 5

西语字符(如a、b、c)通常映射到单个字节。单词hello为5个字节,由于Go字符串为字节切片,因此可输出字符串中特定位置的字节值。在下面的示例中,输出了字符串"hello"的第一个字节

1
2
3
4
s := "hello"
fmt.Printf(s[0])

//outputs 104

由于通过索引访问字符串时,访问的是字节而不是字符,因此显示的是以十进制表示的字节值。而不是字符 h

字符的二进制和十进制表示:

h e l l o
十进制 104 101 108 108 111
二进制 1101000 1100101 1101100 1101100 1101111

处理字符串

给字符串变量赋值后,就可以使用标准库中的 strings 包提供的任何方法。这个包提供了一套完成的字符串处理函数,其文档非常详尽。下面介绍几个字符串处理实例,但要全面了解 strings 包提供的函数,可以阅读文档

将字符串转换为小写

1
2
3
func main() {
fmt.Println(strings.ToLower("VERY"))
}

在字符串中查找字符

处理字符串时,另一个常见的任务是在字符串中查找子串。方法Index提供了这样的功能,它接收的第二个参数就是要查找的子串。如果找到就返回第一个子串的索引号,如果没有则返回 -1

1
2
3
4
func main() {
fmt.Println(strings.Index("test", "te"))
fmt.Println(strings.Index("moon", "sun"))
}

运行输出:

1
2
0
-1

删除字符串中的空格

strings 包提供了很多将字符串某些部分删除的方法。处理来自用户或数据源的输入时,一种常见的任务就是确保开头和末尾没有空格。方法 TrimSpace 提供了这样的功能

1
2
3
func main() {
fmt.Println(strings.TrimSpace(" I don't need all this space "))
}

问题列表

  • 名称”字符串”是怎么来的?

    虽然没有权威答案,但之所以称为”字符串”,是因为它是一系列表示字符的字节

  • 创建字符串后,可对其进行修改吗?

    Go语言中,字符串是不可变的,创建后就不能修改。但可以重新赋值或者拼接


All articles in this blog adopt the CC BY-SA 4.0 agreement unless otherwise stated. Please indicate the source for reprinting!