1.1 什么是string

Go中的字符串是一个字节的切片。可以通过将其内容封装在””中来创建字符串。Go中的字符是Unicode兼容的,并且是utf-8编码,判断长度和输出要考虑兼容性。
Go与Java语言一样,字符串默认是不可变的,保证了线程安全,使用的都是只读对象,无需加锁,且很方便共享内存,不必使用写时复制。

1.2 string基础语法

1.2.1 字符串和字符

Go没有专门的字符类型,如果要存储单个字符(字母),一般使用byte来保存,且使用单引号包裹

  1. var c1 = 'A'
  2. var c2 byte = 'B'
  3. c3 := 'C'
  4. fmt.Println("c1,c2,c3 :", c1, c2, c3)
  5. fmt.Printf("c1=%c,c2=%c,c3=%c\n", c1, c2, c3)
  6. c4 := '我'
  7. c5 := '1'
  8. fmt.Println("c4,c5 :", c4, c5)
  9. fmt.Printf("c4=%c,c5=%c\n", c4, c5)
  10. /*
  11. c1,c2,c3: 65 66 67
  12. c1=A,c2=B,c3=C
  13. c4,c5: 25105 49
  14. c4=我,c5=1
  15. */

1.2.2 定义与修改

Go的修改不能直接修改比如str[1]=”e”,这种改法是错误的,需要转成byte[]进行转换

  1. // 定义
  2. str := "Test测试"
  3. fmt.Println("修改前的str:", str)
  4. strTemp := []byte(str)
  5. strTemp[2] = 'e'
  6. str = string(strTemp)
  7. fmt.Println("修改后的str:", str)
  8. /*
  9. 修改前的str: Test测试
  10. 修改后的str: Teet测试
  11. */

1.2.3 切割

Go中的切割使用很方便语法为:

  1. arr[a:b] // 其中a是开始的索引,b是结束的索引,前闭后开a,b可以不写,a不写意为从头开始切,b不写意为切到尾

示例为:

  1. strNum := "123456"
  2. fmt.Println(strNum[1:4])
  3. fmt.Println(strNum[1:])
  4. fmt.Println(strNum[:4])
  5. /*
  6. 234
  7. 23456
  8. 1234
  9. */

1.2.4 获取长度

字符串获取长度,有以下的规则

  1. 如果是中文,那么使用utf8.RuneCountInString(str)
  2. 如果不是中文,使用utf8.RuneCountInString(str)和len(str)都可以 ```go strNum := “123456” strWord := “hello” strChinese := “你好世界” strChineseAndWord := “hello世界” strChineseAndNum := “世界123” fmt.Println(len(strNum), len(strWord), len(strChinese), len(strChineseAndWord), len(strChineseAndNum))

fmt.Println(utf8.RuneCountInString(strNum), utf8.RuneCountInString(strWord), utf8.RuneCountInString(strChinese), utf8.RuneCountInString(strChineseAndWord), utf8.RuneCountInString(strChineseAndNum)) / 6 5 12 11 9 6 5 4 7 5 /

  1. > 总结:为了避免出现异常和统一性,推荐使用utf8.RuneCountInString_(str_)获取长度;
  2. <a name="HDKft"></a>
  3. ### 1.2.5 字符串遍历
  4. 字符串的遍历有两种方式,一种是通过长度 for i;i<len();i++,一种是通过range,注意区分中文和非中文<br />示例一、遍历非中文:
  5. ```go
  6. s1 := "hello"
  7. // 遍历方式一
  8. for i := 0; i < len(s1); i++ {
  9. fmt.Printf(" %c\n", s1[i])
  10. }
  11. fmt.Println("---------------")
  12. // 遍历方式二
  13. for i, ch := range s1 {
  14. fmt.Printf(" 索引是%d,字符为%c\n", i, ch)
  15. }
  16. /*
  17. h
  18. e
  19. l
  20. l
  21. o
  22. ---------------
  23. 索引是0,字符为h
  24. 索引是1,字符为e
  25. 索引是2,字符为l
  26. 索引是3,字符为l
  27. 索引是4,字符为o
  28. */

示例二、遍历中文

  1. s2 := "你好世界"
  2. // 遍历方式一
  3. for i := 0; i < utf8.RuneCountInString(s2); i++ {
  4. fmt.Printf("%c\n", s2[i])
  5. }
  6. fmt.Println("----------------")
  7. // 遍历方式二
  8. for i, ch := range s2 {
  9. fmt.Printf("索引是%d,字符为%c\n", i, ch)
  10. }
  11. /*
  12. ä
  13. ½
  14. å
  15. ----------------
  16. 索引是0,字符为你
  17. 索引是3,字符为好
  18. 索引是6,字符为世
  19. 索引是9,字符为界
  20. */

总结:为了避免出现异常和统一性,推荐使用range进行遍历;

1.2.6 字符串拼接

使用’+’能够连接字符串,但是该操作并不高效(因为字符串在go中是基本类型,每次拼接都是拷贝了内存!)。
Go1.10提供了类似java的stringBuilder机制进行高效字符串拼接。
示例:(注意这里的示例需要引入’bytes’模块)

  1. str1 := "hello "
  2. str2 := "world"
  3. fmt.Println(str1 + str2)
  4. // 创建字节缓冲
  5. var stringBuilder bytes.Buffer
  6. // 把字符串写入缓冲
  7. stringBuilder.WriteString(str1)
  8. stringBuilder.WriteString(str2)
  9. // 将缓冲以字符串形式输出
  10. fmt.Println(stringBuilder.String())
  11. /*
  12. hello world
  13. hello world
  14. */

1.2.7 strings库常用函数

这里仅仅是几个例子,还有很多可以自己调用测试。

内置的strings模块包含很多常用的方法,使用时,需要引入”strings”模块。

1.2.7.1 获取索引位置

  1. str1 := "This my first step"
  2. // 获取索引位置
  3. var index = strings.Index(str1, "m")
  4. fmt.Printf("%v its index of 'm' is :%v\n", str1, index)
  5. /*
  6. This my first step its index of 'm' is :5
  7. */

1.2.7.2 判断是否包含某个字符串

  1. str1 := "This my first step"
  2. var contain = strings.Contains(str1, "fi")
  3. fmt.Printf("%v whether contain 'fi' :%v\n", str1, contain)
  4. /*
  5. This my first step whether contain 'fi' :true
  6. */

1.2.7.3 替换字符串

  1. // 替换字符串str中old字符串为新的字符串,n表示替换的次数,小于0全部替换
  2. str := "zzzledz"
  3. fmt.Println("replace once result :" + strings.Replace(str, "z", "b", 1)) // 替换1次
  4. str2 := "zzzledz"
  5. fmt.Println("replace second result :" + strings.Replace(str2, "z", "b", 2)) // 替换2次
  6. str3 := "zzzledz"
  7. fmt.Println("replace all result :" + strings.Replace(str3, "z", "b", -1)) //全部替换
  8. /*
  9. replace once result :bzzledz
  10. replace second result :bbzledz
  11. replace all result :bbbledb
  12. */

1.2.7.4 切片(split)

  1. // 字符串切片,返回的是一个[]sring字符串数组
  2. var strArr = strings.Split("one-two-three", "-")
  3. fmt.Println(strArr)
  4. /*
  5. [one two three]
  6. */

1.2.7.5 去除头尾字符

  1. strings.Trim(s,str) 去除s字符串头尾部包含的str字符
  2. strings.TrimPrefix(s,str) 去除s字符串头部包含的str字符
  3. strings.TrimSuffix(s,str) 去除s字符串尾部包含的str字符
  4. strings.Fields(s) 去除s字符串的空白 ```go fmt.Println(strings.TrimPrefix(“zledHellozled”, “zled”)) // 去除头部空格 fmt.Println(strings.TrimSuffix(“zledHellozled”, “zled”)) // 去除头部 fmt.Println(strings.Trim(“zledHellozled”, “zled”)) // 去除尾部 var s = “ BCA D E “ fmt.Println(strings.Fields(s)) // 切割空格,返回[]string数组

/ Hellozled zledHello Hello [BCA D E] /

  1. <a name="8bW9D"></a>
  2. #### 1.2.7.6 自定义拼接符(join)
  3. ```go
  4. var obtStr = "ABC"
  5. obtArr := []string{"+","-","*","/"}
  6. fmt.Println(strings.Join(obtArr, obtStr))
  7. /*
  8. +ABC-ABC*ABC/
  9. */

1.2.8 strconv库常用函数

使用此库,需要引入”strconv”

1.2.8.1 字符串转换

如果只是转换类型,可以直接使用string(obt)将obt转成string类型
在java中遇到 “你好”+123 会将+转变为连接符,而Go语言要求,+号两边数据的类型必须一直,这使得类似的操作变得比较不便
Go提供了strconv包用于字符串与基本类型之间的转换,常用函数有Append,format,parse

  1. // format系列函数把其他类型转换成字符串
  2. a := strconv.Itoa(13)
  3. b := strconv.FormatBool(false)
  4. // 要转换的浮点数,格式标记,精度(数字部分的长度,不包括指数部分),指定浮点类型(32:float32,64:float64)
  5. c := strconv.FormatFloat(123.23, 'g', 12, 64)
  6. // 将 int 型整数 i 转换为字符串形式,base:进位制(2 进制到 36 进制)
  7. d := strconv.FormatInt(1234, 10)
  8. e := strconv.FormatUint(12345, 10)
  9. fmt.Println(a + "哈哈" + b + c + d + e)
  10. /*
  11. 13哈哈false123.23123412345
  12. */

1.2.8.2 字符串拼接

strconv中也包含拼接函数,示例如下:

  1. arr1 := make([]byte, 0, 100) // 返回的总长度是100,第二个参数是长度,第三个参数是用来指定预留的空间长度
  2. arr1 = strconv.AppendInt(arr1, 5467, 10)
  3. arr1 = strconv.AppendBool(arr1, false)
  4. arr1 = strconv.AppendQuote(arr1, "abcdefg")
  5. arr1 = strconv.AppendQuoteRune(arr1, '单')
  6. fmt.Println(string(arr1))
  7. /*
  8. 5467false"abcdefg"'单'
  9. */

1.3 string、rune、byte

有时在对特定的操作时,需要进行转换

  • byte等同于int8,常用来处理ascii字符
  • rune等同于int32,常用来处理unicode或utf-8字符

示例:
比如下面的,字符串反转
方法1,首先是最原始的写法:

  1. str := "zled"
  2. func stringReverse(str string) string {
  3. split := strings.Split(str, "")
  4. for from, to := 0, len(split)-1; from < to; from, to = from+1, to-1 {
  5. split[from], split[to] = split[to], split[from]
  6. }
  7. return strings.Join(split, "")
  8. }
  9. fmt.Println("str 反转后的结果是:", stringReverse(str))
  10. /*
  11. str 反转后的结果是: delz
  12. */

方法2,是使用rune代替一些操作

  1. str := "zled"
  2. func stringReverse(str string) string {
  3. // 变量值交换
  4. runes := []rune(str)
  5. for from, to := 0, len(runes)-1; from < to; from, to = from+1, to-1 {
  6. runes[from], runes[to] = runes[to], runes[from]
  7. }
  8. return string(runes)
  9. }
  10. fmt.Println("str 反转后的结果是:", stringReverse(str))
  11. /*
  12. str 反转后的结果是: delz
  13. */

可以看出使用rune省略了转换和合并的操作,所以有的时候操作string的时候可以转换为rune,然后再进行后续操作。