最近我在论坛中去发现了字符串大小20字符的问题,给“hollowaykeanho”出了相关的答案,而我从中发现了截取字符串的方案并非最理想的方法,因此做了一系列实验并获得高效截取字符串的方法,这篇文章将逐步讲解我实践的过程。
这正是“hollowaykeanho”给出的第一个方案,我想也是很多人想到的第一个方案,利用去的内置切片语法截取字符串:
s:="六边形abcdef " fmt.Println (s [1:4]) >之前我们很快就了解到这是按字节截取,在处理ASCII单字节字符串截取,没有什么比这更完美的方案了,中文往往占多个字节,在utf8编码中是3个字节,如下程序我们将获得乱码数据:
s:="去语言” fmt.Println (s [1:4]) >之前
" hollowaykeanho "给出的第二个方案就是将字符串转换为[]符文,然后按切片语法截取,再把结果转成字符串。
s:="去语言” 拉尔夫-舒马赫:=[]符文(s) fmt.Println(字符串(rs [1:4])) >之前首先我们得到了正确的结果,这是最大的进步。不过我对类型转换一直比较谨慎,我担心它的性能问题,因此我尝试在搜索引擎和各大论坛查找答案,但是我得到最多的还是这个方案,似乎这已经是唯一的解。
我尝试写个性能测试评测它的性能:
包基准 导入( “测试” ) var benchmarkSubString=坝镅允枪雀杩⒌囊恢志蔡坷嘈?编译型,并发型,并具有垃圾回收功能的编程语言。为了方便搜索和识别,有时会将其称为Golang。” var benchmarkSubStringLength=20 func SubStrRunes字符串(字符串,长度int) { 如果utf8.RuneCountInString (s)的在{长度 拉尔夫-舒马赫:=[]符文(s) 返回字符串(rs(长度):) } 返回年代 } func BenchmarkSubStrRunes (b * testing.B) { 我:=0;我& lt;b.N;我+ + { SubStrRunes (benchmarkSubString benchmarkSubStringLength) } } >之前我得到了让我有些吃惊的结果:
美好的:达尔文 goarch: amd64 包裹:github.com/thinkeridea/go-extend/exunicode/exutf8/benchmark BenchmarkSubStrRunes-8 872253 1363 ns/op 336 B/op alloc/op 通过 好的github.com/thinkeridea/go-extend/exunicode/exutf8/benchmark 2.120秒 >之前对69个的字符串截取前20个字符需要大概微1.3秒,这极大的超出了我的心里预期,我发现因为类型转换带来了内存分配,这产生了一个新的字符串,并且类型转换需要大量的计算。
我想改善类型转换带来的额外运算和内存分配,我仔细的梳理了一遍字符串包,发现并没有相关的工具,这时我想到了utf8包,它提供了多字节计算相关的工具,实话说我对它并不熟悉,或者说没有主动(直接)使用过它,我查看了它所有的文档发现utf8。DecodeRuneInString函数可以转换单个字符,并给出字符占用字节的数量,我尝试了如此下的实验:
包基准 导入( “测试” “unicode/utf8 " ) var benchmarkSubString=坝镅允枪雀杩⒌囊恢志蔡坷嘈?编译型,并发型,并具有垃圾回收功能的编程语言。为了方便搜索和识别,有时会将其称为Golang。” var benchmarkSubStringLength=20 func SubStrDecodeRuneInString字符串(字符串,长度int) { var大小、n int 我:=0;我& lt;长度,,n & lt;len(年代);我+ + { _、大?utf8.DecodeRuneInString (s [n:]) n +=大小 } 返回年代(n): } func BenchmarkSubStrDecodeRuneInString (b * testing.B) { 我:=0;我& lt;b.N;我+ + { SubStrDecodeRuneInString (benchmarkSubString benchmarkSubStringLength) } } >之前运行它之后我得到了令我惊喜的结果:
美好的:达尔文 goarch: amd64 包裹:github.com/thinkeridea/go-extend/exunicode/exutf8/benchmark BenchmarkSubStrDecodeRuneInString-8 10774401 105 ns/op 0 B/op 0 alloc/op 通过 好的github.com/thinkeridea/go-extend/exunicode/exutf8/benchmark 1.250秒 >之前较[]符文类型转换效率提升了13倍,消除了内存分配,它的确令人激动和兴奋,我迫不及待的回复了“hollowaykeanho”告诉他我发现了一个更好的方法,并提供了相关的性能测试。
去高效截取字符串的一些思考