一、定义

一个字符串是一个不可改变的字节序列,字符串可以包含任意的数据,
但是通常是用来包含可读的文本,字符串是 UTF-8 字符的一个序列

当字符为 ASCII 码表上的字符时则占用 1 个字节,其它字符根据需要占用2-4 个字节

字符串是一种值类型,且值不可变,即创建某个文本后将无法再次修改这个文本的内容,
更深入地讲,字符串是字节的定长数组。


1. 双引号定义

package main

import "fmt"

func main() {
    s := "lear go 中文测试"
    fmt.Println(s)
}

2. 反引号定义

package main

import "fmt"

func main() {
    s := `第一行
第二行
\r\n
`
    fmt.Println(s)
}

运行输出

第一行
第二行
\r\n

在这种方式下,反引号间换行将被作为字符串中的换行,但是所有的转义字符均无效,文本将会原样输出。


二、遍历字符串

1字节 = 8位gobyte 就是 uint8

type byte = uint8

直接遍历一个字符串

package main

import "fmt"

func main() {
    for key, ch := range "ab我们" {
        fmt.Println(key, ch)
    }
}

其实这里,ch 默认就是 int32,所以和下面写法等价

func main() {
    for key, ch := range []int32("ab我们") {
        fmt.Println(key, ch)
    }
}

运行输出

0 97
1 98
2 25105
5 20204

可以看到中文是占用了3个字节,中文“我们”从下标2跳跃到5了,所以上面例题遇到中文就不准确了


三、使用rune

字符串中的每一个元素叫做“字符”,在遍历或者单个获取字符串元素时可以获得字符。

Go语言的字符有以下两种:

  • 一种是 uint8 类型,或者叫 byte 型,代表了 ASCII 码的一个字符。
  • 另一种是 rune 类型,代表一个 UTF-8 字符,当需要处理中文、日文或者其他复合字符时,则需要用到 rune 类型。rune 类型等价于 int32 类型。
for key, ch := range []rune("ab我们") {
    fmt.Println(key, ch)
}

运行输出

0 97
1 98
2 25105
3 20204

使用rune的时候,遍历输出的下标就是一个顺序的下标了,上一章节例题[]byte(s)修改为[]rune(s)就能支持中文了

使用rune的时候,对字符串进行UTF-8的解码,解出来的每个字符转为Unicode,转的Unicode又放到rune四字节里面返回给我们


四、其它操作

1. UTF-8 库

package main

import (
    "fmt"
    "strings"
    "unicode/utf8"
)

func main() {
    // UTF-8统计字符个数
    fmt.Println(utf8.RuneCountInString("ABC中国人")) // 6
    fmt.Println(len("ABC中国人"))                    // 12

    // UTF-8逐个输出字符
    bytes := []byte("Yes我是中国人")
    for len(bytes) > 0 {
        ch, size := utf8.DecodeRune(bytes)
        bytes = bytes[size:]
        fmt.Printf("%c ", ch)
    } // Y e s 我 是 中 国 人
}

2. strings 库

package main

import (
    "fmt"
    "strings"
)

func main() {

    // slice转字符串
    str := []string{"a", "b", "c"}
    fmt.Println(strings.Join(str, ",")) // a,b,c

    // 字符串转slice
    fmt.Println(strings.Split("AB|CD", "|")) // [AB CD]

    // 统计字符串中子字符串出现的次数,如果第二个参数为空字符串,计算整个字符串的长度
    fmt.Println(strings.Count("中国中国ABAB", "国")) // 2

    // 查找字符串是否存
    fmt.Println(strings.Contains("ABCDE中国", "中")) // true

    // r参数是一个rune,rune在go == int32,相当于就是go中的char
    fmt.Println(strings.ContainsRune("ABC中国", '中')) // true

    // 判断字符串 s 中是否包含 chars 中的任何一个字符
    fmt.Println(strings.ContainsAny("ABCDE", "XYE")) // true

    // 查找子字符串的第一次出现位置,找不到-1
    fmt.Println(strings.Index("abcabc", "b")) // 1

    // 查找字符串最后出现的位置
    fmt.Println(strings.LastIndex("abcabc", "b")) // 4

    // 查找任意存在的字符串第一次出现的位置
    fmt.Println(strings.IndexAny("abcde", "edcba")) // 0

    // 查找任意存在的字符串最后一次出现的位置
    fmt.Println(strings.LastIndexAny("abcde", "edcba")) // 4

    // 小写转大写
    fmt.Println(strings.ToUpper("abcd")) // abcd

    // 根据map小写转大写
    fmt.Println(strings.Map(toUpper, "abcd")) // ABCD

    // 重复字符串
    fmt.Println(strings.Repeat("A", 3)) // AAA

    // 不区分大小写对比
    fmt.Println(strings.EqualFold("ABCD", "abcd")) // true

    // 区分大小写对比
    fmt.Println("ABCD" == "abcd") // false

    // The result will be 0 if a==b, -1 if a < b, and +1 if a > b
    fmt.Println(strings.Compare("a", "b"))

    // 每个元素转为数组
    fmt.Println(strings.Fields("abcd中国")) // [abcd中国]

    // 根据回调函数转数组
    fmt.Println(strings.FieldsFunc("abcd中国", rmAb)) // [cd中国]

    // 首字母大写
    fmt.Println(strings.Title("hello word"))

    // 判断字符串开头
    fmt.Println(strings.HasPrefix("hello word", "hello"))

    fmt.Println(strings.Trim(" hello word", " "))

    //
    fmt.Println(strings.SplitAfter("hellwordhellword", "wo")) // [hellwo rdhellwo rd]

    //
    fmt.Println(strings.SplitN("hellwordhellword", "o", 3)) // [hellw rdhellw rd]

}

func toUpper(r rune) rune {
    return r - 97 + 65
}

func rmAb(r rune) bool {
    return r == 'a' || r == 'b'
}