string
strings The package provides many simple functions for manipulating strings. Generally, common string manipulation requirements can be found in this package. strconv The package provides conversion between basic data types and strings. In Go, there is no implicit type conversion. General type conversion can do this: int32(i) , will i (such as int type) conversion int32 , however, string types and int、float、bool The conversion between other types is not so simple.
Compare with C
-
Go string itself is the biggest improvement, because C doesn't have it, it can only be replaced by character array; -
The length is O (1) because there is a len field, while C is O (n) because it needs to traverse the entire character array; -
Go string is immutable, and the character array of C is variable; -
support ==, !=, >, <, >=, <= Comparison operator; -
support +, += Operator for string concatenation; -
Each character is a Unicode character, which is stored in utf-8 code; -
The declaration of multiline strings is supported.
Source code reading
// string is the set of all strings of 8-bit bytes, conventionally but not // necessarily representing UTF-8-encoded text. A string may be empty, but // not nil. Values of string type are immutable. type string string
-
String can be empty (length is 0), but not nil; -
String objects cannot be modified.
type stringStruct struct { str unsafe.Pointer len int }
stringStruct.str : the first address of the string; stringStruct.len : The length of the string.
// StringHeader is the runtime representation of a string. // It cannot be used safely or portably and its representation may // change in a later release. // Moreover, the Data field is not sufficient to guarantee the data // it references will not be garbage collected, so programs must keep // a separate, correctly typed pointer to the underlying data. type StringHeader struct { Data uintptr Len int }
Common Operations
func Compare(a, b string) int
func EqualFold(s, t string) bool
//The substring substr in s returns true func Contains(s, substr string) bool //If any Unicode code point in chars is in s, return true func ContainsAny(s, chars string) bool //Unicode code point r in s returns true func ContainsRune(s string, r rune) bool
-
Naive matching algorithm -
KMP algorithm -
Rabin Karp algorithm -
Boyer Moore algorithm
func Count(s, sep string) int
fmt.Printf("Fields are: %q", strings.Fields(" foo bar baz ")) Fields are: ["foo" "bar" "baz"]
fmt.Println(strings. FieldsFunc(" foo bar baz ", unicode.IsSpace))
func Fields(s string) []string { return FieldsFunc(s, unicode.IsSpace) }
func Split(s, sep string) []string { return genSplit(s, sep, 0, -1) } func SplitAfter(s, sep string) []string { return genSplit(s, sep, len(sep), -1) } func SplitN(s, sep string, n int) []string { return genSplit(s, sep, 0, n) } func SplitAfterN(s, sep string, n int) []string { return genSplit(s, sep, len(sep), n) }
fmt.Printf("%q\n", strings.Split("foo,bar,baz", ",")) fmt.Printf("%q\n", strings.SplitAfter("foo,bar,baz", ",")) ["foo" "bar" "baz"] ["foo," "bar," "baz"]
//Start with prefix in s func HasPrefix(s, prefix string) bool { return len(s) >= len(prefix) && s[0:len(prefix)] == prefix } //Whether to end with suffix in s func HasSuffix(s, suffix string) bool { return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix }
fmt.Println(strings. HasPrefix("Gopher", "Go")) fmt.Println(strings. HasPrefix("Gopher", "C")) fmt.Println(strings. HasPrefix("Gopher", "")) true false true
//Find the first occurrence of sep in s and return the index of the first occurrence func Index(s, sep string) int //Find the first occurrence of byte c in s and return the index of the first occurrence func IndexByte(s string, c byte) int //The first occurrence position of any Unicode code point in chars in s func IndexAny(s, chars string) int //Find the first occurrence of the character c in s, where c meets f (c) and returns true func IndexFunc(s string, f func(rune) bool) int //The first occurrence position of Unicode code point r in s func IndexRune(s string, r rune) int //There are three corresponding locations for the last occurrence of the search func LastIndex(s, sep string) int func LastIndexByte(s string, c byte) int func LastIndexAny(s, chars string) int func LastIndexFunc(s string, f func(rune) bool) int
fmt.Println(Join([]string{"name=xxx", "age=xx"}, "&")) name=xxx&age=xx
mapping := func(r rune) rune { switch { Case r>='A '&&r<='Z'://convert uppercase letters to lowercase letters return r + 32 Case r>='a '&&r<='z'://Lower case letters are not processed return r case unicode.Is(unicode. Han, r)://Chinese character line breaking return '\n' } Return - 1//Filter all non alphabetic and Chinese characters } fmt.Println(strings. Map (mapping, "Hello you # ¥%... n ('World n, good Hello ^ (&(* gopher..."))) hello world hello gopher
//Replace old in s with new. There are n replacements. //If n<0, there is no limit to the number of replacements, that is, all replacements func Replace(s, old, new string, n int) string //This function directly calls the function Replace (s, old, new, - 1) func ReplaceAll(s, old, new string) string
func ToLower(s string) string func ToLowerSpecial(c unicode. SpecialCase, s string) string func ToUpper(s string) string func ToUpperSpecial(c unicode. SpecialCase, s string) string
//Remove the characters matching any character in the cutset on the left and right of s func Trim(s string, cutset string) string //Remove the character matching any character in the cutset on the left side of s func TrimLeft(s string, cutset string) string //Remove the character matching any character in the cutset on the right side of s func TrimRight(s string, cutset string) string //If the prefix of s is prefix, the string with the prefix removed is returned; otherwise, s does not change. func TrimPrefix(s, prefix string) string //If the suffix of s is suffix, the string with the suffix removed will be returned; otherwise, s will not change. func TrimSuffix(s, suffix string) string //Remove the spacers on the left and right of s. Common spacers include: ' t', ' n', ' v', ' f', ' r', '', U+0085 (NEL) func TrimSpace(s string) string //Remove the characters matching f on the left and right of s func TrimFunc(s string, f func(rune) bool) string //Remove the character matching f to the left of s func TrimLeftFunc(s string, f func(rune) bool) string //Remove the character matching f on the right of s func TrimRightFunc(s string, f func(rune) bool) string
High order operation
r := strings.NewReplacer("<", "<", ">", ">") fmt.Println(r.Replace("This is <b>HTML</b>!")) This is <b>HTML</b>!
type Builder struct { addr *Builder // of receiver, to detect copies by value buf []byte }
//This method writes a byte to b func (b *Builder) WriteByte(c byte) error //The WriteRune method writes a character to b func (b *Builder) WriteRune(r rune) (int, error) //WriteRune method writes byte array p to b func (b *Builder) Write(p []byte) (int, error) //The WriteRune method writes the string s to b func (b *Builder) WriteString(s string) (int, error) //The Len method returns the data length of b. func (b *Builder) Len() int //The Cap method returns the cap of b. func (b *Builder) Cap() int //The Grow method increases b's cap by at least n (possibly more). If n is negative, it will cause panic. func (b *Builder) Grow(n int) //The Reset method will clear all contents of b. func (b *Builder) Reset() //The String method returns the data of b as string. func (b *Builder) String() string
The problem of transferring to slice
func main() { fmt.Println(testing. AllocsPerRun (1, convert1)//Output 1 fmt.Println(testing. AllocsPerRun (1, convert2)//Output 0 } func convert1() { S:="China welcomes you, Beijing welcomes you" sl := []byte(s) for _, v := range sl { _ = v } } func convert2() { S:="Welcome to China" sl := []byte(s) for _, v := range sl { _ = v } }
// The constant is known to the compiler. // There is no fundamental theory behind this number. const tmpStringBufSize = 32 type tmpBuf [tmpStringBufSize]byte func stringtoslicebyte(buf *tmpBuf, s string) []byte { var b []byte if buf != nil && len(s) <= len(buf) { *buf = tmpBuf{} b = buf[:len(s)] } else { b = rawbyteslice(len(s)) } copy(b, s) return b } // rawbyteslice allocates a new byte slice. The byte slice is not zeroed. func rawbyteslice(size int) (b []byte) { cap := roundupsize(uintptr(size)) p := mallocgc(cap, nil, false) if cap != uintptr(size) { memclrNoHeapPointers(add(p, uintptr(size)), cap-uintptr(size)) } *(*slice)(unsafe.Pointer(&b)) = slice{p, size, int(cap)} return }
func main() { fmt.Println(testing. AllocsPerRun (1, convert))//Output 0 } func convert() { S:="China welcomes you, Beijing welcomes you" for _, v := range []byte(s) { _ = v } }
func main() { fmt.Println(testing. AllocsPerRun (1, convert))//Output 0 } func convert() { S:="China welcomes you, Beijing welcomes you" sl := StringToBytes(s) for _, v := range sl { _ = v } } func StringToBytes(s string) (b []byte) { sh := *(*reflect. StringHeader)(unsafe. Pointer(&s)) bh := (*reflect. SliceHeader)(unsafe. Pointer(&b)) bh.Data, bh.Len, bh.Cap = sh.Data, sh.Len, sh.Len return b }
Var x="China welcomes you, Beijing welcomes you" //BenchmarkBytesToString strong conversion func BenchmarkBytesToString(b *testing. B) { for i := 0; i <= b.N; i++ { _ = StringToBytes(x) } } //BenchmarkBytesToStringNormal Native func BenchmarkBytesToStringNormal(b *testing. B) { for i := 0; i <= b.N; i++ { _ = []byte(x) } } BenchmarkBytesToString BenchmarkBytesToString-4 1000000000 0.3269 ns/op BenchmarkBytesToStringNormal BenchmarkBytesToStringNormal-4 36955354 34.13 ns/op
String concatenation
use + func plusConcat(n int, str string) string { s := "" for i := 0; i < n; i++ { s += str } return s } use fmt.Sprintf func sprintfConcat(n int, str string) string { s := "" for i := 0; i < n; i++ { s = fmt.Sprintf("%s%s", s, str) } return s } use strings.Builder func builderConcat(n int, str string) string { var builder strings.Builder for i := 0; i < n; i++ { builder.WriteString(str) } return builder.String() } use bytes.Buffer func bufferConcat(n int, s string) string { buf := new(bytes. Buffer) for i := 0; i < n; i++ { buf.WriteString(s) } return buf.String() } use []byte func byteConcat(n int, str string) string { buf := make([]byte, 0) for i := 0; i < n; i++ { buf = append(buf, str...) } return string(buf) }
BenchmarkPlusConcat-4 15 107333204 ns/op 530997245 B/op 10018 allocs/op BenchmarkSprintfConcat-4 7 154160789 ns/op 832915797 B/op 34114 allocs/op BenchmarkBuilderConcat-4 6637 171604 ns/op 514801 B/op 23 allocs/op BenchmarkBufferConcat-4 7231 164885 ns/op 368576 B/op 13 allocs/op BenchmarkByteConcat-4 7371 248181 ns/op 621298 B/op 24 allocs/op
reference resources
-
https://go.dev/src/runtime/string.go -
https://cs.opensource.google/go/go/ +/tls:src/reflect/value.go -
https://geektutu.com/post/hpg-string-concat.html -
https://books.studygolang.com/The-Golang-Standard-Library-by-Example/chapter02/02.1.html