1. 字符串
1.1 相关概念
在Go语言中,字符串是不可变字节(byte)
,其本身是一个复合结构。字符串内容在初始化之后不可修改。字符串一般用双引号""
或者反引号来创建。用双引号创建的字符串支持转义,但不支持多行书写;用反引号创建的字符串支持多行书写,但是不支持转义。此外,还有一个需要注意的地方,字符串的默认值为""
,而不是"nil"
。
1.2 字符串操作
1.2.1 字符串的创建
func main(){
var a string
a = "aabbcc"
b := "eeffgg"
fmt.Println(a,b)
}
1.2.2 字符串的遍历
Go语言中字符串的遍历有两种方式:以Unicode方式遍历
和 以UTF-8方式遍历
。这两种方式的区别是,以Unicode
方式遍历字符串,每次遍历4个字节,而以UTF-8
方式遍历字符串,每次遍历单个字节。故下方代码中,使用Unicode
方式遍历中文字符串不会出现乱码。
func main(){
a := "啦啦啦"
for i,c := range a{
fmt.Printf("%d:[%c]\n",i,c) // 以rune(或者说Unicode)方式遍历字符串
}
for i:=0;i<len(a);i++{
fmt.Printf("%d:[%c]\n",i,a[i]) // 以byte(或者说UTF-8)方式遍历字符串
}
}
/*
输出结果为:
0:[啦]
3:[啦]
6:[啦]
0:[å]
1:[•]
2:[¦]
3:[å]
4:[•]
5:[¦]
6:[å]
7:[•]
8:[¦]
*/
1.2.3 字符串的"!= ,== , <, > , +, +="操作
判断字符串是否相等需要看字符串中的每个元素是否相等,比较字符串的大小实际上是在比较字符串中第一个字符ASCII码的大小,当第一个字符相同时,再比较第二个字符,以此类推。
func main(){
a := "ab"
b := "cd"
s := a + b
fmt.Println(s) // abcd
fmt.Println(a == b,a != b,a > b,a < b) // false true false true
}
1.2.4 字符串元素的访问
我们可以通过索引值来访问字符串中的元素,但是不能获取元素地址。
func main(){
a := "ab"
b := "cd"
s := a + b
fmt.Println(s[0]) // a
fmt.Println(&s[1]) // cannot take the address of s[1]
}
1.2.5 字符串的切片
字符串以切片语法(起始和结束索引号)返回字串时,其内部依旧指向原字节数组。
func main(){
s := "abcdefghijklmn"
a := s[0:4]
fmt.Printf("%#v\n",(*reflect.StringHeader)(unsafe.Pointer(&s))) // &reflect.StringHeader{Data:0x4cfa7b, Len:14}
fmt.Printf("%#v\n",(*reflect.StringHeader)(unsafe.Pointer(&a))) // &reflect.StringHeader{Data:0x4cfa7b, Len:14}
}
1.2.6 字符串的修改方法
字符串不能直接修改,必须将其转换为可变类型([ ]rune 或 [ ]byte)之后才能修改,待完成之后再改回来。但无论是哪种方法,都需要重新分配内存、复制数据。
func main() {
s := "abcdefghijklmn"
s[3] = "f" // cannot assign to s[3] 不支持直接修改
s1 := []byte(s)
s1[3] = 102
s = string(s1)
fmt.Println(s) // abcfefghijklmn
}
1.3 相关函数
与字符串有关的函数较多,一类是像len()
这样的内置函数,除此之外还有strings
包下操作字符串的相关函数。
1.3.1 len( ),append( )
函数len()
是一个内置函数,它的作用是求字符串的长度。
func main() {
s := "abcdefghijklmn"
fmt.Println(len(s)) // 14
}
函数append()
可以将字符串追加到[ ]byte
内。
func main() {
var bs []byte
bs = append(bs,"asasa"...)
fmt.Println(bs) // [97 115 97 115 97]
}
1.3.2 strings包下的相关函数
查找操作函数:
func Contains(s, substr string) bool
判断给定字符串s中是否包含子串substr, 找到返回true, 找不到返回false。
func main() {
fmt.Println("包含子串返回:", strings.Contains("oldboy", "boy"))
fmt.Println("不包含子串返回:", strings.Contains("oldboy", "girl"))
fmt.Println("子字符串是空字符串返回:", strings.Contains("oldboy", ""))
fmt.Println("原字符串、子字符串都是空字符串返回:", strings.Contains("", ""))
fmt.Println("中文字符串包含子串返回:", strings.Contains("来自东印度的人", "东印度"))
}
/*
输出结果为:
包含子串返回: true
不包含子串返回: false
子字符串是空字符串返回: true
原字符串、子字符串都是空字符串返回: true
中文字符串包含子串返回: true
*/
func Index(s, sep string) int
在字符串s中查找sep所在的位置, 返回位置值, 找不到返回-1。
func main() {
fmt.Println("存在返回第一个匹配字符的位置:", strings.Index("oldboy", "boy"))
fmt.Println("不存在返回:", strings.Index("oldboy", "girl"))
fmt.Println("中文字符串存在返回:", strings.Index("来自东印度的人", "东印度"))
}
/*
输出结果为:
存在返回第一个匹配字符的位置: 3
不存在返回: -1
中文字符串存在返回: 6
*/
func Count(s, sep string) int
统计给定子串sep的出现次数, sep为空时, 返回字符串的长度 + 1。
func main() {
fmt.Println("子字符串出现次数:", strings.Count("oldboy", "o"))
fmt.Println("子字符串为空时, 返回:", strings.Count("oldboy", ""))
}
/*
输出结果为:
子字符串出现次数: 2
子字符串为空时, 返回: 7
*/
重复操作函数:
func Repeat(s string, count int) string
重复s字符串count次, 最后返回新生成的重复的字符串。
func main() {
fmt.Println(strings.Repeat("嘀嗒", 4), "时针它不停在转动") // 嘀嗒嘀嗒嘀嗒嘀嗒 时针它不停在转动
}
替换操作函数:
func Replace(s, old, new string, n int) string
在s字符串中, 把old字符串替换为new字符串,n表示替换的次数,如果n<0会替换所有old子串。
func main() {
fmt.Println(strings.Replace("luck luck luck", "k", "ky", 2))
fmt.Println(strings.Replace("luck luck luck", "k", "ky", -1))
}
/*
输出结果为:
lucky lucky luck
lucky lucky lucky
*/
删除操作函数:
func Trim(s string, cutset string) string
删除在s字符串的头部和尾部中由cutset指定的字符, 并返回删除后的字符串。
func main() {
fmt.Println(strings.Trim(" oldboy ", " ")) // oldboy 删除了空格
}
大小写转换函数:
func Title(s string) string
给定字符串转换为英文标题的首字母大写的格式(不能正确处理unicode标点)。
func ToLower(s string) string
返回将所有字母都转为对应的小写版本的拷贝。
func ToUpper(s string) string
返回将所有字母都转为对应的大写版本的拷贝。
func main() {
fmt.Println(strings.Title("It is never too late to learn."))
fmt.Println(strings.ToLower("It Is Never Too Late To Learn."))
fmt.Println(strings.ToUpper("It is never too late to learn."))
}
/*
输出结果为:
It Is Never Too Late To Learn.
it is never too late to learn.
IT IS NEVER TOO LATE TO LEARN.
*/
前缀后缀函数:
func HasPrefix(s, prefix string) bool
判断字符串是否包含前缀prefix,大小写敏感。
func HasSuffix(s, suffix string) bool
判断s是否有后缀字符串suffix,大小写敏感。
func main() {
fmt.Println("前缀是以old开头的:", strings.HasPrefix("oldboy", "old"))
fmt.Println("后缀是以boy开头的:", strings.HasSuffix("oldboy", "boy"))
}
/*
输出结果为:
前缀是以old开头的: true
后缀是以boy开头的: true
*/
字符串分隔函数:
func Split(s, sep string) []string
用去掉s中出现的sep的方式进行分割,会分割到结尾,并返回生成的所有片段组成的切片(每一个sep都会进行一次切割,即使两个sep相邻,也会进行两次切割)。如果sep为空字符,Split会将s切分成每一个unicode码值一个字符串。
func Fields(s string) []string
返回将字符串按照空白(unicode.IsSpace确定,可以是一到多个连续的空白字符)分割的多个字符串。如果字符串全部是空白或者是空字符串的话,会返回空切片。
func main() {
fmt.Println("Split 函数的用法")
fmt.Printf("%q\n", strings.Split("Linux,Python,Golang,Java", ","))
fmt.Printf("%q\n", strings.Split("a mountain a temple", "a "))
fmt.Printf("%q\n", strings.Split(" abc ", ""))
fmt.Printf("%q\n", strings.Split("", "oldboy"))
fmt.Println("Fields 函数的用法")
fmt.Printf("Fields are: %q\n", strings.Fields(" Linux Python Golang Java "))
}
/*
输出结果为:
Split 函数的用法
["Linux" "Python" "Golang" "Java"]
["" "mountain " "temple"]
[" " "a" "b" "c" " "]
[""]
Fields 函数的用法
Fields are: ["Linux" "Python" "Golang" "Java"]
*/