我似乎总是一遍又一遍地将字符串转换为[] byte到string.这有很多开销吗?有没有更好的办法?
例如,这是一个接受UTF8字符串,规范化,删除重音,然后将特殊字符转换为ASCII等效字符的函数:
var transliterations = map[rune]string{'Æ':"AE",'Ð':"D",'?':"L",'Ø':"OE",'Þ':"Th",'ß':"ss",'æ':"ae",'ð':"d",'?':"l",'ø':"oe",'þ':"th",'Œ':"OE",'œ':"oe"}
func RemoveAccents(s string) string {
b := make([]byte, len(s))
t := transform.Chain(norm.NFD, transform.RemoveFunc(isMn), norm.NFC)
_, _, e := t.Transform(b, []byte(s), true)
if e != nil { panic(e) }
r := string(b)
var f bytes.Buffer
for _, c := range r {
temp := rune(c)
if val, ok := transliterations[temp]; ok {
f.WriteString(val)
} else {
f.WriteRune(temp)
}
}
return f.String()
}
Run Code Online (Sandbox Code Playgroud)
所以我开始使用字符串,因为这是我得到的,然后我将它转换为字节数组,然后返回到字符串,然后再转换为字节数组,然后再转换回字符串.当然这是不必要的,但我无法弄清楚如何不这样做..?它是否真的有很多开销,或者我不必担心过度转换会减慢速度?
(如果有人有时间我还没弄清楚bytes.Buffer实际上是如何工作的,那么初始化一个字符串大小2 倍的缓冲区会不会更好,这是返回值的最大输出大小?)
在 Go 中,strings 是不可变的,因此任何更改都会创建一个新字符串。作为一般规则,从 a 转换string为 abyte或rune切片一次,然后再转换回string一次。为了避免重新分配,对于小型和暂时的分配,如果您不知道确切的数字,请过度分配以提供安全裕度。
例如,
\n\npackage main\n\nimport (\n "bytes"\n "fmt"\n "unicode"\n "unicode/utf8"\n\n "code.google.com/p/go.text/transform"\n "code.google.com/p/go.text/unicode/norm"\n)\n\nvar isMn = func(r rune) bool {\n return unicode.Is(unicode.Mn, r) // Mn: nonspacing marks\n}\n\nvar transliterations = map[rune]string{\n \'\xc3\x86\': "AE", \'\xc3\x90\': "D", \'\xc5\x81\': "L", \'\xc3\x98\': "OE", \'\xc3\x9e\': "Th",\n \'\xc3\x9f\': "ss", \'\xc3\xa6\': "ae", \'\xc3\xb0\': "d", \'\xc5\x82\': "l", \'\xc3\xb8\': "oe",\n \'\xc3\xbe\': "th", \'\xc5\x92\': "OE", \'\xc5\x93\': "oe",\n}\n\nfunc RemoveAccents(b []byte) ([]byte, error) {\n mnBuf := make([]byte, len(b)*125/100)\n t := transform.Chain(norm.NFD, transform.RemoveFunc(isMn), norm.NFC)\n n, _, err := t.Transform(mnBuf, b, true)\n if err != nil {\n return nil, err\n }\n mnBuf = mnBuf[:n]\n tlBuf := bytes.NewBuffer(make([]byte, 0, len(mnBuf)*125/100))\n for i, w := 0, 0; i < len(mnBuf); i += w {\n r, width := utf8.DecodeRune(mnBuf[i:])\n if s, ok := transliterations[r]; ok {\n tlBuf.WriteString(s)\n } else {\n tlBuf.WriteRune(r)\n }\n w = width\n }\n return tlBuf.Bytes(), nil\n}\n\nfunc main() {\n in := "test string\xc3\x9f"\n fmt.Println(in)\n inBytes := []byte(in)\n outBytes, err := RemoveAccents(inBytes)\n if err != nil {\n fmt.Println(err)\n }\n out := string(outBytes)\n fmt.Println(out)\n}\nRun Code Online (Sandbox Code Playgroud)\n\n输出:
\n\ntest string\xc3\x9f\ntest stringss\nRun Code Online (Sandbox Code Playgroud)\n