go语言学习十五 - StringBuilder

package main

import (
        "fmt"
        "strutils"
)

func main() {
        sb := strutils.NewStringBuilder("eg:")

        sb.Append(" hello").Append(" world.")
        sb.AppendFormat(" my name is %s and my age is %d.", "Tom", 22)

        fmt.Print(sb.ToString())
}

package strutils

import (
        "bytes"
        "fmt"
        "strings"
)

type StringBuilder struct {
        buf bytes.Buffer
}

func NewStringBuilder(s ...string) *StringBuilder {
        sb := StringBuilder{}
        sb.buf.WriteString(strings.Join(s, ""))
        return &sb
}

func (sb *StringBuilder) Append(s string) *StringBuilder {
        sb.buf.WriteString(s)
        return sb
}

func (sb *StringBuilder) AppendFormat(f string, s ...interface{}) *StringBuilder {
        sb.buf.WriteString(fmt.Sprintf(f, s...))
        return sb
}

func (sb *StringBuilder) String() string {
        return sb.ToString()
}

func (sb *StringBuilder) ToString() string {
        return sb.buf.String()
}
  • go语言的字符串处理能在字节层面能解决的问题就直接在字节层面解决。这样做性能更高。
  • 字符串和字节数组之间相互转换底层字节无需复制,转换效率 O(1) 与转换长度没有关系。
  • 明白没必要在内置库提供按照 rune 字符取位置的 substring 和 indexOf 函数的原因了。
package strutils

import (
        "strings"
        "unicode/utf8"
)

//实际工作中一般不会要求返回固定位置后的字符串,如果真有这种需求一般固定位置前的字符类型(纯Ascii还是多字节字符)是确定的。
func Substr(str string, s, e int) string {

        l, n := len(str), utf8.RuneCountInString(str)

        if s < 0 || s > n {
                return ""
        }

        if e < 0 || e > n || e < s {
                return str
        }

        if l == n { //pure ascii string
                return str[s:e]
        }
        //utf8 format
        return string([]rune(str)[s:e])
}

//实际需求中,一般是返回某个标识 字符串后的字符串,这种操作完全可以在 byte[] 级别完成,不必调用 utf8 方法
// go 没有提供 rune 层面的 substring(s string, s,e int) string  是有原因的 
func StrStart(str, s string) string {

        i := strings.Index(str,s)
        if i <0 {
                return str
        }
        
        return str[i:]
}

package main

import (
        "fmt"
)

func main() {
        
        s := "你好,世界.æ" //汉字:3byte; ascii:1byte; 英语音标字符:2byte
        fmt.Println(strings.Index(s,"好")) //3
        fmt.Println(strings.IndexRune(s,'好')) //3 
        //返回索引1 的 IndexXXX 函数 go 内置库没有提供,结合没有提供按照 rune 位置的 substring 考虑,这样的IndexXXX也是不需要的。

        for i, b := range []byte(s) {
                fmt.Printf("%d %d\n", i, b) //i=0~15 ; 3*4+2*1+1*2 = 16
        }

        fmt.Println("=============")

        n := len(s)
        for i:=0;i<n;i++ {
                fmt.Printf("%d %d\n", i, s[i]) //效果同上
        }

        for i, b := range []rune(s) {
                //按rune字符迭代
                fmt.Printf("%d %d %c,", i, b,b) //0 20320 你,1 22909 好,2 44 ,,3 19990 世,4 30028 界,5 46 .,6 230 æ
        }

}