go语言字符串及字符串函数

一、go语言字符串原理

  • 和c语言类似,go语言中的字符串实际上也是一个字符数组.而且是一个只读字符数组.

如字符串:

  1. var str = "HELLO,GOLANG"

基存储的结构如下:

go字符串存储结构

1、读取字符串某个位置上的字符

因为字符串的本质是一个只读的字节数组,因此,我们可以通过读数组元素的方式来读取字符串某个位置上的字符,如:

  1. fmt.Println(str[0]) //输出:72,对应ASCII码中的字符A
2、修改字符串某个位置上的字符.

因为字符串是一个只读的字符数组,因此,它是无法像数组一样,修改某个索引对应的元素值.

我们只能通过修改整个字符串的值来实现,但是这个修改的字符串其实是一个新的字符串.

3、字符串与字符数组之间的转换

因为字符串本质上是只读字符数组,因此它们之间是可以类型转换的.

  • 字符串转换成字符数组,通过[]byte类型函数即可(如果是中文可通过[]rune类型函数来转换)
  • 字符数组转成字符串,通过string类型函数即可
  1. //字符串转字符数组
  2. var str = "HELLO,GOLANG"
  3. var strArr = []byte(str)
  4. fmt.Println(strArr)
  5. //字符数组转字符串
  6. var domainArr = []byte{'S', 'H', 'I', 'X', 'I', 'N', 'K', 'E', '.', 'C', 'O', 'M'}
  7. var domainStr = string(domainArr)
  8. fmt.Println(domainStr)
4、字符串拼接

golang的字符串拼接,与JAVA,javascript等大数据编程语言一样,都是通过+来拼接的(当然也可以通过fmt.Sprintf来实现)

  1. var str = "Hello,Golang!"
  2. str += "Welcome to golang world!"
  3. fmt.Println(str) //输出:Hello,Golang!Welcome to golang world!
5、字符串表示
  • 使用双引号(“”)将字符串中的特殊字符进行解析
  • 使用单引号(‘’)来表示字符
  • 使用``表示的字符串会原样输出,不会解析
  1. poem := "劝君莫惜金缕衣,\n劝君惜取少年时.\n花开堪折直须折,\n莫待无花空折枝."
  2. originPoem := `劝君莫惜金缕衣,\n劝君惜取少年时.\n花开堪折直须折,\n莫待无花空折枝.`
  3. ch1 := '中'
  4. ch2 := 'a'
  5. fmt.Println(poem) //\n都换成换行
  6. fmt.Println(originPoem) //\n转义字符会原样输出,不会换行
  7. fmt.Printf("%c\n", ch1)
  8. fmt.Printf("%c\n", ch2)

二、字符串函数

golang中的字符串函数在strings这个包中

1、匹配子串
(1) 匹配前缀 HasPrefix
  • 作用:判断目标字符串是否以prefix的子串开始
  • 用法:HasPrefix(s string, prefix string)
  • 参数:
    • s:目标字符串
    • prefix:前缀子串
  • 返回值:bool(如果满足条件返回true,否则为false)
  • 例子:
  1. str := "hello world"
  2. fmt.Println(strings.HasPrefix(str, "hello")) //true
  3. fmt.Println(strings.HasPrefix(str, "Hello")) //false
(2) 匹配后缀 HasSuffix
  • 作用:判断目标字符串是否以suffix的子串结束
  • 用法:HasSuffix(s string, suffix string)
  • 参数:
    • s:目标字符串
    • suffix:后缀子串
  • 返回值:bool(如果满足条件返回true,否则为false)
  • 例子:
  1. contentType := "image/gif"
  2. fmt.Println(strings.HasSuffix(contentType, "gif"))   //true
  3. fmt.Println(strings.HasSuffix(contentType, "Gif")) //false
(3) 是否包含子串 Contains
  • 作用:判断目标字符串是包含suffix的子串结束
  • 用法:Contains(s string, substr string)
  • 参数:
    • s:目标字符串
    • substr:子串
  • 返回值:bool(如果包含返回true,否则为false)
  • 例子:
  1. userAgent := "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"
  2. if strings.Contains(userAgent, "Chrome") {
  3. fmt.Println("Chrome浏览器")
  4. } else {
  5. fmt.Println("非Chrome浏览器")
  6. }
(4) 是否包含某个字符 ContainsRune
  • 作用:判断目标字符串是包含某个字符ch(它不仅能判断ASCII字符,也可以判断unicode字符,即可以用来判断是否包含某个中文字)
  • 用法:ContainsRune(s string, ch rune)
  • 参数:
    • s:目标字符串
    • ch:字符
  • 返回值:bool(如果包含返回true,否则为false)
  • 例子:
  1. content := "这是一篇博文,包含各种互联网技术,比如区块链、人工智能、大数据、云计算、物联网等"
  2. fmt.Println(strings.Contains(content, "区块链")) //true,是可以匹配中文的
  3. fmt.Println(strings.ContainsRune(content, '区')) //true
(5) 是否包含指定子串的任意一个字符 ContainsAny
  • 作用:判断目标字符串是包含某个子字符串中的任意一个字符(只有一个就可以)
  • 用法:ContainsAny(s string, chars string)
  • 参数:
    • s:目标字符串
    • chars:子字符串
  • 返回值:bool(如果包含返回true,否则为false)
  • 例子:
  1. content := "这是一篇博文,包含各种互联网技术,比如区块链、人工智能、大数据、云计算、物联网等"
  2. fmt.Println(strings.ContainsAny(content, "人网云他he")) //true
2、位置查找
(1)子串在字符串中第一次出现的位置 Index
  • 作用:判断子串在字符串第一次出现的位置
  • 用法:Index(s string, substr string)
  • 参数:
    • s:目标字符串
    • substr:子字符串
  • 返回值:int(存在返回位置索引值,不存在返回-1)
  • 例子:
  1. title := "golang未来发展方向探究、go开发者职业生涯规划"
  2. fmt.Println(strings.Index(title, "开发者")) //35
  3. fmt.Println(len("开发者")) //9(utf8编码,每个汉字占3个字节)
  4. fmt.Println(utf8.RuneCountInString("开发者")) //3
  5. fmt.Println(strings.Index(title, "go")) //0
(2)子串在字符串中最后一次出现的位置 LastIndex
  • 作用:判断子串在字符串最后一次出现的位置
  • 用法:LastIndex(s string, substr string)
  • 参数:
    • s:目标字符串
    • substr:子字符串
  • 返回值:int(存在返回位置索引值,不存在返回-1)
  • 例子:
  1. title := "golang未来发展方向探究、go开发者职业生涯规划"
  2. fmt.Println(strings.Index(title, "go")) //0
  3. fmt.Println(strings.LastIndex(title, "go")) //33
(3)某个字符在字符串的位置
  • IndexByte:用于ASCII编码等
  • IndexRune:可用于Unicode编码
  1. line := "abcD莫欺少年穷,bug满栈飞"
  2. fmt.Println(strings.IndexByte(line, 'D')) //3
  3. fmt.Println(strings.IndexRune(line, '栈')) //26
3、大小写转换
(1)将字符串转换为大写 ToUpper
  1. fmt.Println(strings.ToUpper("very Good")) //VERY GOOD
(2)将字符串转换为大写 ToLower
  1. fmt.Println(strings.ToLower("Welcome to Golang World")) //welcome to golang world
(3)返回s中每个单词的首字母都改为大写的字符串(类似于PHP中的Ucwords函数)
  1. fmt.Println(strings.Title("my name is jeff")) //My Name Is Jeff
4、去掉字符串两侧的子串
(1)去掉字符串两侧的空格TrimSpace(和其他语言的trim很像)
  1. p := " 总有一些 , 哪里有 "
  2. fmt.Println(p) //输出: 总有一些 , 哪里有
  3. fmt.Println(strings.TrimSpace(p)) //输出:总有一些 , 哪里有
(2)去掉字符串两侧指定字符子串 Trim
  1. p := " 总有一些 , 哪里有 "
  2. p1 := "abc有一些abc"
  3. fmt.Println(strings.Trim(p, " ")) //与TrimSpace效果一样
  4. fmt.Println(strings.Trim(p1, "abc")) //输出:有一些
(3)去掉字符串一侧的指定字符串
  • TrimLeft:去掉左侧所有的指定子字符串
  • TrimRight:去掉右侧所有的指定子字符串
  • TrimPrefix:去掉字符串指定的前缀(只去掉一次)
  • TrimSuffix:去掉字符串指定的后缀(只去掉一次)
  1. fmt.Println(strings.TrimLeft(p1, "abc")) //有一些abcabc
  2. fmt.Println(strings.TrimRight(p1, "abc")) //abcabc有一些
  3. fmt.Println(strings.TrimPrefix(p1, "abc")) //abc有一些abcabc
  4. fmt.Println(strings.TrimSuffix(p1, "abc")) //abcabc有一些abc
5、字符串分割与拼接
(1)字符串分割 Split

这里以解析url为例(在net/url中有相关的解析,这里通过字符串分割函数来实现,这里的函数请不要用于生产环境,因为产不严谨)

  1. type UrlStruct struct {
  2. Scheme string
  3. Host string
  4. Path string
  5. Uri string
  6. Query string
  7. Params map[string]interface{}
  8. Hash string
  9. }
  10. func parseUrl(s string) UrlStruct {
  11. urlStruct := UrlStruct{Scheme:"http"}
  12. tmpArr := strings.Split(s, "//")
  13. if len(tmpArr) == 2 {
  14. if tmpArr[0] != "" {
  15. urlStruct.Scheme = strings.TrimRight(tmpArr[0], ":")
  16. }
  17. hashArr := strings.Split(tmpArr[1], "#")
  18. if len(hashArr) == 2 && hashArr[1] != "" {
  19. urlStruct.Hash = hashArr[1]
  20. }
  21. uriArr := strings.Split(hashArr[0], "?")
  22. if len(uriArr) == 2 && uriArr[1] != "" {
  23. urlStruct.Query = uriArr[1]
  24. var paramMap map[string]interface{}
  25. paramMap = make(map[string]interface{})
  26. paramsArr := strings.Split(uriArr[1], "&")
  27. for _, v := range paramsArr {
  28. paramArr := strings.Split(v, "=")
  29. paramMap[paramArr[0]] = paramArr[1]
  30. }
  31. urlStruct.Params = paramMap
  32. }
  33. pathArr := strings.SplitN(uriArr[0], "/", 2)
  34. urlStruct.Host = pathArr[0]
  35. urlStruct.Path = pathArr[1]
  36. urlStruct.Uri = strings.TrimPrefix(tmpArr[1], pathArr[0])
  37. }
  38. return urlStruct
  39. }
  40. func main() {
  41. url := "https://www.shixinke.com/go/golang-data-type-coversion?version=2.0.5&ua=chrome#title"
  42. fmt.Println(parseUrl(url))
  43. /*
  44. * Scheme : https
  45. * Host : www.shixinke.com
  46. * Path : go/golang-data-type-coversion
  47. * Uri : /go/golang-data-type-coversion?version=2.0.5&ua=chrome#title
  48. * Query : version=2.0.5&ua=chrome
  49. * Params : {version : 2.0.5, ua : chrome}
  50. * Hash : title
  51. */
  52. }
(2)字符串拼接 Join
  1. func buildQueryString(params map[string]string) string {
  2. var queryString = ""
  3. var paramsArr []string
  4. for k, v := range params {
  5. val := k + "="+v
  6. paramsArr = append(paramsArr, val)
  7. }
  8. queryString = strings.Join(paramsArr, "&")
  9. return queryString
  10. }
  11. func main() {
  12. var params map[string]string = map[string]string{
  13. "version":"2.0.5",
  14. "id":"12",
  15. "checked":"true",
  16. }
  17. fmt.Println(buildQueryString(params)) //version=2.0.5&id=12&checked=true
  18. }
6、字符串替换和其他函数
(1)字符串替换repalce
  • 用法:Replace(str string, old string, new string, n int)
  • 参数:

    • str:源字符串

    • old:被替换的子串

    • new:是用来替换的新的子串

    • n:来指定替换前n个子串,如果小于0表示替换所有

  • 返回值:新字符串
  1. var htmlStr = "第一段内容<br>第二段内容<br>第三段内容"
  2. fmt.Println(strings.Replace(htmlStr, "<br>", "\n", -1))
  3. /*
  4. 第一段内容
  5. 第二段内容
  6. 第三段内容
  7. */
  8. fmt.Println(strings.Replace(htmlStr, "<br>", "\n", 1))
  9. /*
  10. 第一段内容
  11. 第二段内容<br>第三段内容
  12. */
(2) 字符串是否相同
  • 不区分大小写:EqualFold

    它判断两个字符串,当大写、小写、标题三种格式字符相同视为相同.当相同时返回true,否则返回false

    1. fmt.Println(strings.EqualFold("Hello", "hello")) //true
    2. fmt.Println(strings.EqualFold("HELLO", "Hello")) //true
    3. fmt.Println(strings.EqualFold("hello golang", "HellO GoLang")) //true
  • 区分大小写:Compare

 这个函数相当于使用==来比较两个字符串,只不过,当两个字符串相等时,它返回0

  1. var str1 = "I love golang"
  2. var str2 = "I love golang"
  3. var str3 = "I Love Golang"
  4. fmt.Println(strings.Compare(str1, str2)) //0
  5. fmt.Println(strings.Compare(str1, str3)) //1
  6. fmt.Println(str1 == str2) //true
  7. fmt.Println(str2 == str3) //false
7、通过函数库实现其他字符串函数
(1)实现截取子字符串函数Substring和Substr

Substring(s string, start int, end int)

  • 功能:截取字符串从start到end为止的子字符串
  • 参数:
    • s : 源字符串,被截取的字符串
    • start:超始位置索引值
    • end : 结束位置索引值
  • 实现原理:因为字符串的底层是byte数组(切片),先将字符串换成byte切片(实际是rune切片),再通过切片方法来截取字符串.
  • 疑问:为啥不用byte切片,而是rune切片.(因为byte其实是int8,rune是int32,byte在无符号时,最大只能到255,此时无法截取中文)
  1. func Substring(s string, start int , end int) string {
  2. var strLen = len(s)
  3. if end > strLen || end < start || start > strLen || start < 0 {
  4. return ""
  5. }
  6. if start == 0 && end == strLen {
  7. return s
  8. }
  9. var runeArr = []rune(s)
  10. return string(runeArr[start:end])
  11. }

调用函数:

  1. var testStr = "English,中文,we,我们"
  2. fmt.Println(Substring(testStr, 7, 12)) //,中文,w

Substr(s string, start int, length int)

  • 功能:截取字符串从start开始,截取length个字符为止的子字符串
  • 参数:
    • s : 源字符串,被截取的字符串
    • start:超始位置索引值
    • length : 截取的子串长度(一个中文也为1)
  • 实现原理:和Substring一致.
  1. func Substr(s string, start int, length int) string {
  2. var strLen = len(s)
  3. var end = start + length
  4. if end > strLen || end < start || start > strLen || start < 0 {
  5. return ""
  6. }
  7. if start == 0 && end == strLen {
  8. return s
  9. }
  10. var runeArr = []rune(s)
  11. return string(runeArr[start:end])
  12. }

调用函数:

  1. var testStr = "English,中文,we,我们"
  2. fmt.Println(Substr(testStr, 6, 5)) //h,中文,
(2)实现首字母大写 Ucfirst
  • 原理:将字符串转换为字符数组(切片),将首字母转换为大小(首先首字母必须是字母,即ASCCI码在97和122之间,另外大小写的码值相差32,即a与A相差32)
  1. func Ucfirst(s string) string {
  2. var bytes = []byte(s)
  3. if bytes[0] >= 97 && bytes[0] <= 122 {
  4. bytes[0] = bytes[0] - 32
  5. return string(bytes)
  6. } else {
  7. return s
  8. }
  9. }
(3)实现函数名或变量名驼峰法与下划线法相互转换:ToCamel、ToUnderline

ToCamel

注:

  • 这里要用到上面的自定义的Ucfirst函数
  • 使用标准库中的Split函数来分割字符串,使用Join函数将数组合并式成字符串
  1. /**
  2. 将下划线表示法改成驼峰法
  3. @param s : 源字符串
  4. @param uf:是否首字母大写(即是否大驼峰法)
  5. */
  6. func ToCamel(s string, uf bool) string {
  7. if len(s) < 2 {
  8. return s
  9. }
  10. var namesArr = strings.Split(s, "_")
  11. if len(namesArr) == 1 {
  12. return s
  13. }
  14. for i, v := range namesArr {
  15. if i == 0 && !uf {
  16. continue
  17. }
  18. namesArr[i] = Ucfirst(v)
  19. }
  20. return strings.Join(namesArr, "")
  21. }
  22. //fmt.Println(ToCamel("get_user_name", true))  结果为:GetUserName

ToUnderline

  1. func ToUnderline(s string, uf bool) string {
  2. if len(s) < 2 {
  3. return s
  4. }
  5. var namesArr = []byte(s)
  6. var tempBytes []byte
  7. for i, v := range namesArr {
  8. if i == 0 {
  9. if !uf {
  10. v += 32
  11. }
  12. tempBytes = append(tempBytes, v)
  13. continue
  14. }
  15. if v >= 65 && v <= 90 {
  16. tempBytes = append(tempBytes, byte('_'), v + 32)
  17. } else {
  18. tempBytes = append(tempBytes, v)
  19. }
  20. }
  21. return string(tempBytes)
  22. }
  23. //fmt.Println(ToUnderline("GetUserName", false)) //get_user_name