Chinaunix首页 | 论坛 | 博客
  • 博客访问: 16961
  • 博文数量: 125
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1290
  • 用 户 组: 普通用户
  • 注册时间: 2020-11-26 14:30
文章分类

全部博文(125)

文章存档

2021年(42)

2020年(80)

我的朋友

分类: Python/Ruby

2021-01-06 17:34:05

  编程语言有很多,而每个编程语言都离不开字符串,那么你知道GO语言字符串有哪些吗?我们一起来看看吧。

  Go语言的字符串是一个用UTF-8编码的变宽字符序列,它的每一个字符都用一个或多个字节表示 。

  在Go语言中,没有字符类型,字符类型是rune类型,rune是int32的别称。可使用 []byte() 获取字节,使用 []rune() 获取字符,可对中文进行转换。

  定义字符串

  第一种,双引号,用来创建可解析的字符串字面量 (支持转义,但不能用来引用多行);

  str := "Go语言字符串\n不能跨行赋值"

  第二种,反引号,用来创建原生的字符串字面量 ,这些字符串可能由多行组成(不支持任何转义序列),原生的字符串字面量多用于书写多行消息、HTML以及正则表达式。

  str := `Go原生原格式字符串

  可以跨行`

  注意:单引号不能用于定义字符串,单引号用于定义Go语言的一个特殊类型 rune,类似其他语言的byte但又不完全一样,是指码点字面量(Unicode code point),不做任何转义的原始内容。

  连接字符串

  第一种,直接使用 "+" 运算符链接

  str := "hello" + "oldboy"

  golang 里面的字符串都是不可变的,每次运算都会产生一个新的字符串,所以会产生很多临时的无用的字符串,不仅没有用,还会给 gc 带来额外的负担,所以性能比较差。

  注意:连接跨行字符串时,"+" 必须在上一行末尾,否则导致编译错误。

  第二种,使用 fmt.Sprintf() 链接

  str := fmt.Sprintf("%s,%s", "hello", "oldboy")

  内部使用 []byte 实现,不像直接运算符这种会产生很多临时的字符串,但是内部的逻辑比较复杂,有很多额外的判断,还用到了 interface,所以性能也不是很好。

  第三种,使用 strings.Join() 链接

  str := strings.Join([]string{"hello", "oldboy"}, ",")

  join会先根据字符串数组的内容,计算出一个拼接之后的长度,然后申请对应大小的内存,一个一个字符串填入,在已有一个数组的情况下,这种效率会很高,但是本来没有,去构造这个数据的代价也不小。

  第四种,使用 buffer.WriteString() 链接

  var buffer bytes.Buffer

  buffer.WriteString("hello")

  buffer.WriteString(",")

  buffer.WriteString("oldboy")

  str := buffer.String()

  这个比较理想,可以当成可变字符使用,对内存的增长也有优化。

  总结:

  1. 在已有字符串数组的场合,使用 strings.Join() 能有比较好的性能;

  2. 在一些性能要求较高的场合,尽量使用 buffer.WriteString() 以获得更好的性能;

  3. "+" 运算符在较少字符串连接的场景下性能最好,而且代码更简短清晰,可读性更好;

  4. 如果需要拼接的不仅仅是字符串,还有数字之类的其他需求的话,可以考虑 fmt.Sprintf()。

  字符串长度

  第一种,将字符串转换为 []rune 后调用 len 函数进行统计

  package main

  import (

  "fmt"

  )

  func main() {

  str := "hello oldboy"

  length := len([]rune(str))

  fmt.Println(length)

  }

  在 Golang 中,如果字符串中出现中文字符不能直接调用 len 函数来统计字符串字符长度,这是因为在 Go 中,字符串是以 UTF-8 为格式进行存储的,在字符串上调用 len 函数,取得的是字符串包含的 byte 的个数。

  第二种,使用 bytes.Count() 统计

  func Count(s, sep []byte) int

  计算字节切片sep在字节切片s中非重叠显示的个数,如果 sep 为 nil,则返回 s 中的字符个数 + 1。

  package main

  import (

  "bytes"

  "fmt"

  )

  func main() {

  str := "hello oldboy"

  length := bytes.Count([]byte(str), nil) - 1

  fmt.Println(length)

  }

  第三种,使用 strings.Count() 统计

  func Count(s, sep string) int

  判断字符sep在字符串s中出现的次数,没有找到则返回-1,如果为空字符串("")则返回字符串的长度+1。

  package main

  import (

  "fmt"

  "strings"

  )

  func main() {

  str := "hello oldboy"

  length := strings.Count(str, "") - 1

  fmt.Println(length)

  }

  第四种,使用 utf8.RuneCountInString() 统计

  func RuneCountInString(s string) (n int)

  返回 s 字符串长度,可以正常解析中文,一个中文被当做一个字符。

  package main

  import (

  "fmt"

  "unicode/utf8"

  )

  func main() {

  str := "hello oldboy"

  length := utf8.RuneCountInString(str)

  fmt.Println(length)

  }

  字符串操作

  使用索引号 "[ ]" 返回子串。 返回的字符串依然指向原字节数组,仅修改了指针和长度属性。实例如下:

  package main

  import (

  "fmt"

  )

  func main() {

  str := "hello, oldboy"

  s1 := str[0:5]

  s2 := str[7:13]

  fmt.Println(s1, s2)

  }

  运行结果:

  hello oldboy

  修改字符串,可先将其转换成 []rune 或 []byte,完成后再转换为 string。无论哪种转换,都会重新分配内存,并复制字节数组。实例如下:

  package main

  import "fmt"

  func main() {

  str1 := "hello oldboy"

  s1 := []byte(str1)

  s1[0] = 'H'

  fmt.Println(string(s1))

  str2 := "鸟宿池边树,僧推月下门。"

  s2 := []rune(str2)

  s2[7] = '敲'

  fmt.Println(string(s2))

  }

  运行结果:

  Hello oldboy

  鸟宿池边树,僧敲月下门。

阅读(76) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~