在GO中字符串作为基本的类型,和c语言不同,c没有原生的字符串类型,c语言使用的是字符数组来表示字符串,并以字符指针来传递字符串。
1.字符串的表示
在Go语言中,字符串的值是不可变的,当创建一个字符串之后,无法再修改这个字符串内容,在GO中字符串是一个定长字符数组。
package main
import (
"fmt"
)
var (
value1 float64
)
func main() {
s := "aA你2"
fmt.Println("字符串长度:", len(s))
for i := 0; i < len(s); i++ {
fmt.Println(s[i])
}
//结果是:字符串长度: 6
97 //a
65 //A
228 //你
189 //你
160 //你
50 //2
/* 下面代码会报错,字符串能不值不能修改*/
// s := "你好,"
// t := s
s += "世界。" //字符串可以连接,但原字符不会改变
fmt.Println(s)
//aA你2世界。
}
非解释字符串
func main() {
str1 := `苟利国家生死以,\n
岂因祸福避趋之` //注意!键盘tab上门那个 ~ 的按键的点
str2 := "今天天气\n真好"
fmt.Println(str1)
fmt.Println(str2)
}
结果:
苟利国家生死以,\n
岂因祸福避趋之
今天天气
真好
注意上面的反单引号和双引号区别,首先单引号可以跨行,并且引号内的所有内容都会直接输出,包括转义字符换行,而双引号不能换行,且会解析转义字符。
操作字符串
func main() {
s := "abcd你"
fmt.Println(len(s)) // 长度7
for i := 0; i < len(s); i++ {
fmt.Println(s[i])
}
/* 输出 97
100
99
98
228
189
160 */
/*从上面字符串能看到汉字占3个字节,一共7个字节长度 */
// c := s[len(s)]
// fmt.Println(len(s), c)
/*这两行代码会报错,因为字符串没有这个索引值(从0开始算,长度是7,但是最后一个字节索引是6)*/
fmt.Println(s[0:7]) //s[0:7] 表示基于s字符串的第0个字节开始到第7字节(不包含第7个)生成一个新的字符串。生成的新字符串将包含7-0字节。也就是说如果要截取字符串,需要注意并不包含最后的那个字符。
fmt.Println(s[4:]) //返回 :你
fmt.Println(s[:3]) //返回 :adc
fmt.Println(s[:4]) //返回 :abcd
fmt.Println(s[:5]) //返回不出来 你 字 返回的是:abcd�
fmt.Println(s[3:]) //返回 :d你
}
连接字符串
func main() {
s := "abcd你"
fmt.Println(s[4:] + "好") //你好
fmt.Println(s[3:] + "好") //d你好
str := "你好," + "Go!" //由于编译器自动加分号的原因,加号必须放在第一行
fmt.Println(str) //你好,Go!
}
字符串遍历
func main() {
s := "我是一个中国人"
for i := 0; i < len(s); i++ {
fmt.Printf("%c", s[i])
fmt.Printf("%d=%v\n", i, s[i]) //输出单字节值
}
fmt.Printf("\n")
//使用这种方法无法输出我们想要的结果,因为单纯使用len方法是不能遍历字符串每个字符,只是遍历其一个字节是无法显示完成的字符串,因此遍历字符串要用range方式
// For-each range 循环 这种格式的循环可以对字符串、数组、切片等进行迭代输出元素。
for _, v := range s {
fmt.Printf("%c", v)
}
//输出:我是一个中国人
fmt.Printf("\n")
t := []int{1, 2, 3, 4}
for x, y := range t {
fmt.Println(x, y)
}
//其中x是键,y是值 类似键值对输出
输出: 0 1
1 2
2 3
3 4
}
字符串的修改
因为Go中字符串不能修改,也就是不能用s[i]的方式修改字符串的UTF-8编码,如果确实要修改
可以将字符串内容复制到另一个可写变量中,然后修改,一般用[]byte和[]rune格式,如果字符中的字节进行修改,则转换为[]rune格式,转换过程会自动复制数据
//[]byte格式
func main() {
s := "hello 世界"
b := []byte(s) //转换为[]byte,自动复制数据
b[5] = ',' //修改[]byte
fmt.Printf("%s\n", s)
fmt.Printf("%s\n", b)
}
输出:
hello 世界
hello,世界
//[]rune格式
func main() {
s := "hello 世界"
r := []rune(s) //转换为[]rune,自动复制数据
r[6] = '中' //修改[]rune
r[7] = '国'
fmt.Println(s) //s不能被修改
fmt.Println(string(r)) //转换为字符串,又一次复制数据
}
输出:
hello 世界
hello 中国
包含判断(前后缀包含)
对于基本类型来说,字符串执行操作会比较复杂, Go语言标准库中有一个名为strings的库
package main
import (
"fmt"
"strings" //stings包
)
var (
value12 float64
)
func main() {
str := "This is an example of a string"
fmt.Printf("Dose the string \"%s\" have have prftix %s?", str, "Th")
fmt.Printf("\n")
fmt.Printf("%t\n", strings.HasPrefix(str, "Th")) //HasPrefix判断前缀是否包含指定字符串
fmt.Printf("%t\n", strings.HasSuffix(str, "string")) //HasSuffix判断后缀是否包含指定字符串
fmt.Printf("%t\n", strings.Contains(str, "example")) //contains 判断是否包含指定字符串
fmt.Println(strings.Contains("foo", "")) //ture
fmt.Println(strings.ContainsAny("foo", "")) //false
//Contains和ContainsAny不同的点在于,第二个能够匹配更广泛的内容,它可以容纳Unicode字符
}
返回结果:
Dose the string "This is an example of a string" have have prftix Th?
true
true
true
true
false
索引
在strings包中Index就可以返回指定字符/串的第一个字符索引值,如果不存在相应的字符串,则返回-1。
func main() {
str := "Hi, I'm Job, Hi."
fmt.Printf("%d\n", strings.Index(str, "J")) // 8
fmt.Printf("%d\n", strings.Index(str, "H")) // 0
fmt.Printf("%d\n", strings.Index(str, "Fuck")) //-1
}
非ascll编码字符可以用IndexRune函数对字符进行定位
func main() {
str := "我是张三"
fmt.Printf("%d\n", strings.IndexRune(str, '张')) //6
}
替换
替换字符串最常用的方法是用正则匹配去替换,灵活度更高,但是Go语言对于比较基础的字符串替换已经打包在strings中了,例如:Replace函数
func main() {
str := "我是张三"
new := "李四"
old := "张三"
n := 1
fmt.Println(strings.Replace(str, old, new, n))
/*其中n参数表示匹配到第几个old,如果n为-1则代表匹配所有*/
}
结果:我是李四
统计
func main() {
str := "Golang is cool, right?"
var many0 = "o"
fmt.Printf("%d\n", strings.Count(str, many0)) // o 出现3次
fmt.Printf("%d\n", strings.Count(str, "oo")) // oo 出现1次
}
结果:
3
1
字符数量
func main() {
str := "你好世界"
/*len([]rune(str))是两个方法的组合,先把字符串通过[]rune转化,然后统计长度*/
fmt.Printf("%d\n", len([]rune(str)))
/* 第二个方法是通过utf8包中的RuneCountInString函数统计,一般更推荐第二种,如果没有用utf8其他的函数可以没必要用这种方法用第一种也可以*/
fmt.Println(utf8.RuneCountInString(str))
}
结果:
4
4
大小写转化
var (
lower string
upper string
)
func main() {
str := "How are you?"
fmt.Printf("%s\n", str)
fmt.Printf("%s\n", strings.ToLower(str)) //ToLower转化成小写
fmt.Printf("%s\n", strings.ToUpper(str)) //ToUpper转化成大写
}
结果:
How are you?
how are you?
HOW ARE YOU?
修剪
func main() {
str := "!!! Go !!!"
fmt.Printf("%q\n", strings.Trim(str, "! "))
fmt.Printf("%q\n", strings.Trim(str, " ! "))
fmt.Printf("%q\n", strings.Trim(str, "!")) //注意第二个参数区别会造成什么结果
str1 := "女朋友是最美的"
fmt.Printf("%q\n", strings.Trim(str1, "女"))
fmt.Printf("%q\n", strings.Trim(str1, "的"))
fmt.Printf("%q\n", strings.Trim(str1, "女最")) //只减掉一个女字 最字没有减掉
}
结果:
"Go"
"Go"
" Go "
"朋友是最美的"
"女朋友是最美"
"朋友是最美的"
分割
func main() {
fmt.Printf("%q\n", strings.Split("a,b,c", ","))
fmt.Printf("%q\n", strings.Split("a boy a computer a pig", "a"))
fmt.Printf("%q\n", strings.Split("qwe", ""))
}
结果:
["a" "b" "c"]
["" " boy " " computer " " pig"]
["q" "w" "e"]
插入
func main() {
str := "The quick brown fox jumps over the lazy dog 厉害"
strSli := strings.Fields(str)
//strings.Fields函数用于把字符串转换为字符串切片,然后听过range获得每个切片的值,最后使用string.Join向字符串插入指定字符,除此之外还能使用字节缓冲bytes.Buffer连接字符串
fmt.Printf("%s\n", strSli)
for _, val := range strSli {
fmt.Printf("%s ", val)
}
fmt.Println() //换行
str2 := strings.Join(strSli, ";")
fmt.Printf("%s\n", str2)
}
结果:
[The quick brown fox jumps over the lazy dog 厉害]
The quick brown fox jumps over the lazy dog 厉害
The;quick;brown;fox;jumps;over;the;lazy;dog;厉害