1.1 什么是string
Go中的字符串是一个字节的切片。可以通过将其内容封装在””中来创建字符串。Go中的字符是Unicode兼容的,并且是utf-8编码,判断长度和输出要考虑兼容性。
Go与Java语言一样,字符串默认是不可变的,保证了线程安全,使用的都是只读对象,无需加锁,且很方便共享内存,不必使用写时复制。
1.2 string基础语法
1.2.1 字符串和字符
Go没有专门的字符类型,如果要存储单个字符(字母),一般使用byte来保存,且使用单引号包裹
var c1 = 'A'
var c2 byte = 'B'
c3 := 'C'
fmt.Println("c1,c2,c3 :", c1, c2, c3)
fmt.Printf("c1=%c,c2=%c,c3=%c\n", c1, c2, c3)
c4 := '我'
c5 := '1'
fmt.Println("c4,c5 :", c4, c5)
fmt.Printf("c4=%c,c5=%c\n", c4, c5)
/*
c1,c2,c3: 65 66 67
c1=A,c2=B,c3=C
c4,c5: 25105 49
c4=我,c5=1
*/
1.2.2 定义与修改
Go的修改不能直接修改比如str[1]=”e”,这种改法是错误的,需要转成byte[]进行转换
// 定义
str := "Test测试"
fmt.Println("修改前的str:", str)
strTemp := []byte(str)
strTemp[2] = 'e'
str = string(strTemp)
fmt.Println("修改后的str:", str)
/*
修改前的str: Test测试
修改后的str: Teet测试
*/
1.2.3 切割
Go中的切割使用很方便语法为:
arr[a:b] // 其中a是开始的索引,b是结束的索引,前闭后开a,b可以不写,a不写意为从头开始切,b不写意为切到尾
示例为:
strNum := "123456"
fmt.Println(strNum[1:4])
fmt.Println(strNum[1:])
fmt.Println(strNum[:4])
/*
234
23456
1234
*/
1.2.4 获取长度
字符串获取长度,有以下的规则
- 如果是中文,那么使用utf8.RuneCountInString(str)
- 如果不是中文,使用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 /
> 总结:为了避免出现异常和统一性,推荐使用utf8.RuneCountInString_(str_)获取长度;
<a name="HDKft"></a>
### 1.2.5 字符串遍历
字符串的遍历有两种方式,一种是通过长度 for i;i<len();i++,一种是通过range,注意区分中文和非中文<br />示例一、遍历非中文:
```go
s1 := "hello"
// 遍历方式一
for i := 0; i < len(s1); i++ {
fmt.Printf(" %c\n", s1[i])
}
fmt.Println("---------------")
// 遍历方式二
for i, ch := range s1 {
fmt.Printf(" 索引是%d,字符为%c\n", i, ch)
}
/*
h
e
l
l
o
---------------
索引是0,字符为h
索引是1,字符为e
索引是2,字符为l
索引是3,字符为l
索引是4,字符为o
*/
示例二、遍历中文
s2 := "你好世界"
// 遍历方式一
for i := 0; i < utf8.RuneCountInString(s2); i++ {
fmt.Printf("%c\n", s2[i])
}
fmt.Println("----------------")
// 遍历方式二
for i, ch := range s2 {
fmt.Printf("索引是%d,字符为%c\n", i, ch)
}
/*
ä
½
å
----------------
索引是0,字符为你
索引是3,字符为好
索引是6,字符为世
索引是9,字符为界
*/
总结:为了避免出现异常和统一性,推荐使用range进行遍历;
1.2.6 字符串拼接
使用’+’能够连接字符串,但是该操作并不高效(因为字符串在go中是基本类型,每次拼接都是拷贝了内存!)。
Go1.10提供了类似java的stringBuilder机制进行高效字符串拼接。
示例:(注意这里的示例需要引入’bytes’模块)
str1 := "hello "
str2 := "world"
fmt.Println(str1 + str2)
// 创建字节缓冲
var stringBuilder bytes.Buffer
// 把字符串写入缓冲
stringBuilder.WriteString(str1)
stringBuilder.WriteString(str2)
// 将缓冲以字符串形式输出
fmt.Println(stringBuilder.String())
/*
hello world
hello world
*/
1.2.7 strings库常用函数
这里仅仅是几个例子,还有很多可以自己调用测试。
内置的strings模块包含很多常用的方法,使用时,需要引入”strings”模块。
1.2.7.1 获取索引位置
str1 := "This my first step"
// 获取索引位置
var index = strings.Index(str1, "m")
fmt.Printf("%v its index of 'm' is :%v\n", str1, index)
/*
This my first step its index of 'm' is :5
*/
1.2.7.2 判断是否包含某个字符串
str1 := "This my first step"
var contain = strings.Contains(str1, "fi")
fmt.Printf("%v whether contain 'fi' :%v\n", str1, contain)
/*
This my first step whether contain 'fi' :true
*/
1.2.7.3 替换字符串
// 替换字符串str中old字符串为新的字符串,n表示替换的次数,小于0全部替换
str := "zzzledz"
fmt.Println("replace once result :" + strings.Replace(str, "z", "b", 1)) // 替换1次
str2 := "zzzledz"
fmt.Println("replace second result :" + strings.Replace(str2, "z", "b", 2)) // 替换2次
str3 := "zzzledz"
fmt.Println("replace all result :" + strings.Replace(str3, "z", "b", -1)) //全部替换
/*
replace once result :bzzledz
replace second result :bbzledz
replace all result :bbbledb
*/
1.2.7.4 切片(split)
// 字符串切片,返回的是一个[]sring字符串数组
var strArr = strings.Split("one-two-three", "-")
fmt.Println(strArr)
/*
[one two three]
*/
1.2.7.5 去除头尾字符
- strings.Trim(s,str) 去除s字符串头尾部包含的str字符
- strings.TrimPrefix(s,str) 去除s字符串头部包含的str字符
- strings.TrimSuffix(s,str) 去除s字符串尾部包含的str字符
- 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] /
<a name="8bW9D"></a>
#### 1.2.7.6 自定义拼接符(join)
```go
var obtStr = "ABC"
obtArr := []string{"+","-","*","/"}
fmt.Println(strings.Join(obtArr, obtStr))
/*
+ABC-ABC*ABC/
*/
1.2.8 strconv库常用函数
1.2.8.1 字符串转换
如果只是转换类型,可以直接使用string(obt)将obt转成string类型
在java中遇到 “你好”+123 会将+转变为连接符,而Go语言要求,+号两边数据的类型必须一直,这使得类似的操作变得比较不便
Go提供了strconv包用于字符串与基本类型之间的转换,常用函数有Append,format,parse
// format系列函数把其他类型转换成字符串
a := strconv.Itoa(13)
b := strconv.FormatBool(false)
// 要转换的浮点数,格式标记,精度(数字部分的长度,不包括指数部分),指定浮点类型(32:float32,64:float64)
c := strconv.FormatFloat(123.23, 'g', 12, 64)
// 将 int 型整数 i 转换为字符串形式,base:进位制(2 进制到 36 进制)
d := strconv.FormatInt(1234, 10)
e := strconv.FormatUint(12345, 10)
fmt.Println(a + "哈哈" + b + c + d + e)
/*
13哈哈false123.23123412345
*/
1.2.8.2 字符串拼接
strconv中也包含拼接函数,示例如下:
arr1 := make([]byte, 0, 100) // 返回的总长度是100,第二个参数是长度,第三个参数是用来指定预留的空间长度
arr1 = strconv.AppendInt(arr1, 5467, 10)
arr1 = strconv.AppendBool(arr1, false)
arr1 = strconv.AppendQuote(arr1, "abcdefg")
arr1 = strconv.AppendQuoteRune(arr1, '单')
fmt.Println(string(arr1))
/*
5467false"abcdefg"'单'
*/
1.3 string、rune、byte
有时在对特定的操作时,需要进行转换
- byte等同于int8,常用来处理ascii字符
- rune等同于int32,常用来处理unicode或utf-8字符
示例:
比如下面的,字符串反转
方法1,首先是最原始的写法:
str := "zled"
func stringReverse(str string) string {
split := strings.Split(str, "")
for from, to := 0, len(split)-1; from < to; from, to = from+1, to-1 {
split[from], split[to] = split[to], split[from]
}
return strings.Join(split, "")
}
fmt.Println("str 反转后的结果是:", stringReverse(str))
/*
str 反转后的结果是: delz
*/
方法2,是使用rune代替一些操作
str := "zled"
func stringReverse(str string) string {
// 变量值交换
runes := []rune(str)
for from, to := 0, len(runes)-1; from < to; from, to = from+1, to-1 {
runes[from], runes[to] = runes[to], runes[from]
}
return string(runes)
}
fmt.Println("str 反转后的结果是:", stringReverse(str))
/*
str 反转后的结果是: delz
*/
可以看出使用rune省略了转换和合并的操作,所以有的时候操作string的时候可以转换为rune,然后再进行后续操作。