Golang: 高效截取的字符串

  • Post author:
  • Post category:golang


当我们需要从一串很长的字符串中获取一部分时,是不是有点恼火,特别是有中文在里面的时候,就是那些一个字符占几个字节的数据。



字节切片截取的方式

我们可能会常做的事就是像这样:

s := "abcdefghijk"
fmt.Println(s[1:4])

这样获取字符串部分数据傻没毛病,正常情况下,golang中字符串是不变的,我们直接采取这种方式可以达到我们的目的。

我们知道这是按字节截取,在处理

ASCII

单字节字符串截取,没有什么比这更完美的方案了,但是当我们的字符串中出现了中文数据,中文往往占多个字节,在 utf8 编码中是3个字节,如下程序我们将获得乱码数据:

s := "Go 你好呀!"
fmt.Println(s[1:4])



类型转换 []rune

上面中文乱码的情况,我们可以使用golang内置的rune,将字符串转为[]rune,然后按切片语法截取,再把结果转成字符串。

s := "Go 你好呀!"
rs := []rune(s)
fmt.Println(strings(rs[1:4]))

这种方式相信大家都知道它的弊端,因为类型转换带来了内存分配,这产生了一个新的字符串,并且类型转换需要大量的计算,不仅耗时多了,而且还分配了内存。



好方法

我们知道字符串底层是有一个字节数据保存实际数据的,我们想要达到截取含多字节的字符串时,只需要知道截取的范围中,起始字节索引和结束字节的索引,就可以继续采用字节切片的方式截取字符串啦!



utf8

包中,它提供了多字节计算相关的工具,其中就有,

utf8.DecodeRuneInString

函数可以转换单个字符,并给出字符占用字节的数量,

我们写一个方法:

func SubStrDecodeRuneInString(s string, length int) string {
	 var size, n int
	 for i := 0; i < length && n < len(s); i++ {
		  _, size = utf8.DecodeRuneInString(s[n:])
		  n += size
	 }
 	return s[:n]
}

写个性能测试来检测一下效果:

var str = "Go语言是Google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的编程语言。为了方便搜索和识别,有时会将其称为Golang。"
var subLen= 20
func BenchmarkSubStrDecodeRuneInString(b *testing.B) {
	for i := 0; i < b.N; i++ {
	 	SubStrDecodeRuneInString(str, subLen)
	}
}
goos: darwin
goarch: amd64
pkg: test/utf8/benchmark
BenchmarkSubStrDecodeRuneInString-8     10874723               100 ns/op               0 B/op          0 allocs/op
PASS
ok      test/utf8/benchmark     1.050s

有点小激动,效果还不错

当然,还有一种方法,就是利用

rang

,range 是按字符迭代的,并非字节。使用 range 迭代字符串时返回字符起始索引和对应的字符,这样,我们就也可以写出一个方法出来啦!

func Str(str string, length int) string {
	var i,n int
	for i = range str {
		if length == n{
			break
		}
		n++
	}
	return str[:i]
}

知识是死的,方法是活,加油学习每一天!!!



版权声明:本文为qq_41257365原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。