Go 基础:字符与字符串(string)数据类型

字符与字符串

Go 内置两种字符类型:

  • 一种是 byte 的字节类类型(byteuint 的别名)
  • 另一种是表示 Unicode 编码的字符 rune。rune 在 Go 内部是 int32类型的别名,占用 4 个字节。

Go 语言默认的字符编码是 UTF-8 类型,如果需要特殊的编码转换,则使用 Unicode/UTF-8 标准包。

Go 语言将字符串作为一种原生的基本数据类型,字符串初始化可以使用 字符串字面量

  • 字面量:用于表达源代码中一个固定值的符号,源于 C 语言中的称呼,其它语言有称为常量

  • 字符串字面量(stringliteral)是指双引号引住的一系列字符,双引号中可以没有字符,可以只有一个字符,也可以有很多个字符。

字符串是不可变值类型,内部用指针指向 UTF-8 字节数组

  • 默认值是空字符串 ""
  • 可以用索引号访问字符串的字节,如 str[i]。
  • 不能用序号获取字节元素指针,如 &str[i] 是非法的。
  • 不可变类型,无法修改字节数组的值。
  • 字节数组尾部不包含 NULL。

字符串类型底层是一个二维的数据结构,一个是指针指向字节数组的起点,另一个是长度。例如:

1
2
3
4
type stringStruct struct {
str unsafe.Pointer
len int
}

字符串声明

所有类型声明都是一样的。

  1. 显示完整声明

    1
    var a = "hello, word"
  2. 短类型声明::= 只能出现在函数内(包括方法内),只是 Go 编译器自动进行数据类型推断。

    Go 支持多个类型变量同时声明并赋值,但不建议这么使用,不易阅读

    1
    2
    a := "hello"
    a, b := "hello", "world"

字符串处理

使用索引访问字节

字符串是常量,可以通过类似数组的索引访问其字节单元,但是不能修改某个字节的
值。例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package main

import "fmt"

var a = "hello,world"

var b = "hello,世界!"

func main() {

// 访问字符串的字节单元
b := a[0]
fmt.Println(b) // 104
fmt.Println(a[1]) // 101
fmt.Println(string(a[2])) // l

c := "abc"
fmt.Println(c[0] == '\x61', c[1] == 'b') //true true
}

不做转义处理

使用 ` 定义不做转义处理的原始字符串,支持跨行

1
2
3
4
5
6
7
8
9
package main

import "fmt"

func main() {
str2 := `ab\r\n\x00c`
fmt.Println(str2)
}
// 输出结果:ab\r\n\x00c

连符串跨行连接

连符串使用 + 符号来连接,跨行连接的 + 必须在上一行的结尾,否则会报错。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main

import "fmt"

func main() {
str3 := "hello, " + "world"
fmt.Println(str3)

str4 := "hello, " +
"world"
fmt.Println(str4)
}
// 输出结果:
// hello, world
// hello, world

获取字符串子串

因字符串底层是个二维的数据结构,所以可以使用索引长度(单位:字节) 来获取字符串的子串。

注意:中文是 三个字节 表示一个汉字,如果长度不是 3 的整数倍就会显示乱码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main

import "fmt"

func main() {
str5 := "hello, world"
fmt.Println(str5[0:4]) // 指定从索引0开始, 4个字节
fmt.Println(str5[1:]) // 索引1开始, 到结尾
fmt.Println(str5[:4]) // 默认人0开始, 4个字节

str6 := "中国人民共和国"
fmt.Println(str6[0:3])
fmt.Println(str6[3:])
fmt.Println(str6[:6])
}
// 输出结果:
// hell
// ello, world
// hell
// 中
// 国人民共和国
// 中国

单引号表示Unicode

Go 源码采用的是 UTF-8 的编码方式,UTF-8 的字符占用的字节数可以有 1~4 个字节,Rune 字符常量使用 ''将其括住。

支持 \uFFFF、\U7FFFFFFF、\xFF 格式, 对应 rune 类型,UCS-4。

1
2
3
4
5
6
7
8
9
10
11
12
package main

import "fmt"

func main() {
fmt.Printf("%T\n", 'a')
var str7, str8 rune = '\u6211', '们' // 定义为 run 类型
fmt.Println(str7 == '我', string(str8) == "\xe4\xbb\xac")
}
// 输出结果:
// int32 (rune 是 int32 的别名)
// true true

修改字符串

要修改字符串,可先将其转换成 []rune 或 []byte

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package main

import "fmt"

func main() {
str9 := "hello"
str10 := []byte(str9) // 转换成 []byte
str10[1] = 'H'
fmt.Println(string(str10))

str11 := "电脑"
str12 := []rune(str11) // 转换成 []rune
str12[1] = '话'
fmt.Println(string(str12))
}
// 输出结果:
// hHllo
// 电话

循环遍历字符串

有两种方式,但都是基于 for 循环。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package main

import "fmt"

func main() {
str13 := "hello,word"
for i, v := range str13 { // i 是索引,v 是值
fmt.Println(i, string(v))
}
fmt.Println(".................................")
for i := 0; i < len(str13); i++ {
fmt.Println(i, string(str13[i]))
}
}

strings处理

strings 是 Go 自带的字符串工具类。

判断开始字符串

strings.HasPrefix(src, dest),返回 bool

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package main

import (
"fmt"
"strings"
)

func main() {
str := "hello,world"

res0 := strings.HasPrefix(str, "http")
res01 := strings.HasPrefix(str, "hello")

fmt.Println(res0) // false
fmt.Println(res01) // true
}

判断结尾字符串

strings.HasPrefix(src, dest),返回 bool

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package main

import (
"fmt"
"strings"
)

func main() {
str := "hello,world"

res2 := strings.HasSuffix(str, "world")
res3 := strings.HasSuffix(str, "word")

fmt.Println("res2 =", res2)
fmt.Println("res3 =", res3)
}

判断字符首次出现的索引位

strings.Index(src, dest),返回 int

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package main

import (
"fmt"
"strings"
)

func main() {
str := "hello,world"

num1 := strings.Index(str, "l")
num2 := strings.Index(str, "o")
num3 := strings.Index(str, "i")
fmt.Println("num1 =", num1) // 2
fmt.Println("num2 =", num2) // 4
fmt.Println("num3 =", num3) // -1
}

判断字符最后出现的索引位

strings.LastIndex(src, dest),返回 int

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package main

import (
"fmt"
"strings"
)

func main() {
str := "hello,world"

num4 := strings.LastIndex(str, "l")
num5 := strings.LastIndex(str, "o")
num6 := strings.LastIndex(str, "i")
fmt.Println("num4 =", num4) // 9
fmt.Println("num5 =", num5) // 7
fmt.Println("num6 =", num6) // -1
}

字符串替换

  • Replace(s, old, new string, n int) string:指定替换次数
  • ReplaceAll(s, old, new string) string:替换所有,实际调上面的方法,n 传的是 -1,表示不限制次数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package main

import (
"fmt"
"strings"
)

func main() {
str1 := "hello,world, world"
res5 := strings.Replace(str1, "h", "H", 1)
res6 := strings.Replace(str1, "o", "O", 2)
res7 := strings.ReplaceAll(str1, "l", "L")
fmt.Println("res5 =", res5)
fmt.Println("res6 =", res6)
fmt.Println("res7 =", res7)
}

// 输出结果:
// Hello,world, world
// hellO,wOrld, world
// heLLo,worLd, worLd

求重复出现的次数

Count(s, substr string) int:返回整数

1
2
3
4
5
6
7
8
9
10
11
12
13
package main

import (
"fmt"
"strings"
)

func main() {
str1 := "hello,world, world"
fmt.Println(strings.Count(str1, "l")) // 4
fmt.Println(strings.Count(str1, "o")) // 3
fmt.Println(strings.Count(str1, "z")) // 0
}

重复n次返回

Repeat(s string, count int) string,返回 copy n 次的新字符串

1
2
3
4
5
6
7
8
9
10
11
12
package main

import (
"fmt"
"strings"
)

func main() {
str2 := "hello,world"
fmt.Println(strings.Repeat(str2, 1)) // hello,world
fmt.Println(strings.Repeat(str2, 2)) // hello,worldhello,world
}

大小写转换

  • ToLower(s string) string:转小写
  • ToUpper(s string) string:转大写
1
2
3
4
5
6
7
8
9
10
11
12
package main

import (
"fmt"
"strings"
)

func main() {
str2 := "Hello,World"
fmt.Println(strings.ToLower(str2)) // hello,world
fmt.Println(strings.ToUpper(str2)) // HELLO,WORLD
}

移除指定内容

  • Trim(s, cutset string) string:去掉首尾指定的字符
  • TrimSpace(s string) string:去掉首尾空格
  • TrimPrefix(s, prefix string) string:去掉前缀指定的字符
  • TrimSuffix(s, suffix string) string:去掉后缀指定的字符
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main

import (
"fmt"
"strings"
)

func main() {
fmt.Println(strings.Trim("Hello,WorldH", "H")) // ello,World
fmt.Println(strings.TrimSpace(" Hello,WorldH ")) //【Hello,WorldH】
fmt.Println(strings.TrimPrefix("Hello", "H")) // ello
fmt.Println(strings.TrimSuffix("Hello", "o")) // Hell
fmt.Println(strings.TrimLeft("Hello", "H")) // ello
fmt.Println(strings.TrimRight("Hello", "o")) //Hell
}

字符串切割

  • Fields(s string) []string:返回空格分隔的子串
  • Split(s, sep string) []string:指定分隔符,返回分隔的子串
1
2
3
4
5
6
7
8
9
10
11
package main

import (
"fmt"
"strings"
)

func main() {
fmt.Println(strings.Fields("Hello World")) // [Hello World]
fmt.Println(strings.Split("Hello Word, Word", ",")) // [Hello Word Word]
}

字符数组拼接

  • Join(elems []string, sep string) string:传入字符串数组和连接符,返回字符串
1
2
3
4
5
6
7
8
9
10
11
12
package main

import (
"fmt"
"strings"
)

func main() {
str3 := []string{"hello", "world", "best"}
rest := strings.Join(str3, "_")
fmt.Println(rest) // hello_world_best
}