去高效截取字符串的一些思考

  

最近我在论坛中去发现了字符串大小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”告诉他我发现了一个更好的方法,并提供了相关的性能测试。

去高效截取字符串的一些思考