strings
The strings package implements simple functions to operate on UTF-8 encoded strings. Simply put, it is a toolkit for operating on strings.
Official documentation: strings package - strings - Go Packages
TIP
Go natively supports UTF8 characters, and all string operations are based on UTF8.
Import
import (
"strings"
)The following will explain commonly used functions with examples.
Clone String
func Clone(s string) stringAllocates a new memory for the copied replica. If an empty string is passed, no memory is allocated and an empty string is returned.
func TestClone(t *testing.T) {
ori := "hello 世界"
copys := strings.Clone(ori)
fmt.Println(ori, copys)
fmt.Println(&ori, ©s)
}=== RUN TestClone
hello 世界 hello 世界
0xc00005e5d0 0xc00005e5e0
--- PASS: TestClone (0.00s)
PASSCompare Strings
func Compare(a, b string) intCompares strings a and b lexicographically. If a > b, returns 1; if a < b, returns -1; if a = b, returns 0.
func TestCompare(t *testing.T) {
fmt.Println(strings.Compare("abc", "abe"))
fmt.Println(strings.Compare("abcd", "abe"))
fmt.Println(strings.Compare("abijk", "abe"))
fmt.Println(strings.Compare("abe", "abe"))
}=== RUN TestCompare
-1
-1
1
0
--- PASS: TestCompare (0.00s)
PASSContains String
func Contains(s, substr string) boolDetermines whether string s contains substring substr.
func TestContains(t *testing.T) {
fmt.Println(strings.Contains("abcdefg", "a"))
fmt.Println(strings.Contains("abcdefg", "abc"))
fmt.Println(strings.Contains("abcdefg", "ba"))
}=== RUN TestContains
true
true
false
--- PASS: TestContains (0.00s)
PASSfunc ContainsAny(s, chars string) boolDetermines whether any character's Unicode code point in string chars is within string s. In other words, whether s contains any character from chars.
func TestContainsAny(t *testing.T) {
fmt.Println(strings.ContainsAny("abcedfg", "bac"))
fmt.Println(strings.ContainsAny("abcedfg", "gfdecba"))
}=== RUN TestContainsAny
true
--- PASS: TestContainsAny (0.00s)
PASSfunc ContainsRune(s string, r rune) boolDetermines whether string s contains rune r.
func TestContainsRune(t *testing.T) {
fmt.Println(strings.ContainsRune("abcedf", 'a'))
fmt.Println(strings.ContainsRune("abcedf", 'b'))
fmt.Println(strings.ContainsRune("你好世界", '你'))
}=== RUN TestContainsRune
true
true
true
--- PASS: TestContainsRune (0.00s)
PASSCount Substring Occurrences
func Count(s, substr string) intReturns the number of times substring substr appears in string s.
func TestCount(t *testing.T) {
fmt.Println(strings.Count("3.1415926", "1"))
fmt.Println(strings.Count("there is a girl", "e"))
fmt.Println(strings.Count("there is a girl", ""))
}=== RUN TestCount
2
2
16
--- PASS: TestCount (0.00s)
PASSCut String
func Cut(s, sep string) (before, after string, found bool)Cuts the first occurrence of substring sep in s and returns the result after cutting.
before- The string before the cut substring positionafter- The string after the cut substring positionfound- Whether the substring was found
func TestCut(t *testing.T) {
show := func(s, sep string) {
before, after, found := strings.Cut(s, sep)
fmt.Printf("Cut(%q, %q) = %q, %q, %v\n", s, sep, before, after, found)
}
show("Hello world", " ")
show("Hello world", "world")
show("Hello world", "Hello")
show("Hello world", "Hello world")
}=== RUN TestCut
Cut("Hello world", " ") = "Hello", "world", true
Cut("Hello world", "world") = "Hello ", "", true
Cut("Hello world", "Hello") = "", " world", true
Cut("Hello world", "Hello world") = "", "", true
--- PASS: TestCut (0.00s)
PASSCase-Insensitive Equality
func EqualFold(s, t string) boolReturns whether strings s and t are equal ignoring case.
func TestEqualFold(t *testing.T) {
fmt.Println(strings.EqualFold("你好", "你好"))
fmt.Println(strings.EqualFold("Hello", "Hello"))
fmt.Println(strings.EqualFold("Hello", "hELLO"))
}=== RUN TestEqualFold
true
true
true
--- PASS: TestEqualFold (0.00s)
PASSSplit String
func Fields(s string) []stringfunc FieldsFunc(s string, f func(rune) bool) []stringThe former splits the string by whitespace, while the latter uses the return value of function f to decide whether to split the string.
func TestField(t *testing.T) {
fmt.Printf("%q\n", strings.Fields(" a b c d e f g "))
fmt.Printf("%q\n", strings.FieldsFunc("a,b,c,d,e,f,g", func(r rune) bool {
return r == ','
}))
}=== RUN TestField
["a" "b" "c" "d" "e" "f" "g"]
["a" "b" "c" "d" "e" "f" "g"]
--- PASS: TestField (0.00s)
PASSFind Prefix/Suffix
func HasPrefix(s, prefix string) boolfunc HasSuffix(s, suffix string) boolThe former searches for a prefix, and the latter searches for a suffix. If interested, you can check the source code implementation here, which is quite clever.
func TestPreSuffix(t *testing.T) {
str := "abbc cbba"
fmt.Println(strings.HasPrefix(str, "abb"))
fmt.Println(strings.HasSuffix(str, "bba"))
}=== RUN TestPreSuffix
true
true
--- PASS: TestPreSuffix (0.00s)
PASSSubstring Position
Returns the index of the first occurrence of a substring:
func Index(s, substr string) intReturns the index of the first occurrence of any character from the substring:
func IndexAny(s, chars string) intReturns the index of the first occurrence of a rune:
func IndexRune(s string, r rune) intExample:
func TestIndex(t *testing.T) {
fmt.Println(strings.Index("abcdefg", "bc"))
fmt.Println(strings.IndexAny("abcdefg", "cb"))
fmt.Println(strings.IndexRune("abcdefg", 'g'))
}=== RUN TestIndex
1
1
6
--- PASS: TestIndex (0.00s)
PASSReturns the index of the last occurrence of a substring:
func LastIndex(s, substr string) intReturns the index of the last occurrence of any character from the substring:
func LastIndexAny(s, chars string) intExample:
func TestLastIndex(t *testing.T) {
fmt.Println(strings.LastIndex("abcdefga", "a"))
fmt.Println(strings.LastIndexAny("abcdefghisa", "ba"))
}Map and Replace String
Map returns a copy of string s with all its characters modified according to the mapping function. If the mapping returns a negative value, the character is deleted from the string without replacement.
func Map(mapping func(rune) rune, s string) stringExample:
func TestMap(t *testing.T) {
fmt.Println(strings.Map(func(r rune) rune {
return r - 32
}, "abcdefghijk"))
fmt.Println(strings.Map(func(r rune) rune {
return r + 32
}, "ABCDEFGHIJK"))
fmt.Println(strings.Map(func(r rune) rune {
if r < 'F' {
return -1
} else {
return r
}
}, "ABCDEFGHIJK"))
}Output:
=== RUN TestMap
ABCDEFGHIJK
abcdefghijk
FGHIJK
--- PASS: TestMap (0.00s)
PASSRepeat String
Replicates the string according to the given count. If negative, it will cause a panic.
func Repeat(s string, count int) stringExample:
func TestRepeat(t *testing.T) {
fmt.Println(strings.Repeat("a", 10))
fmt.Println(strings.Repeat("abc", 10))
}Output:
=== RUN TestRepeat
aaaaaaaaaa
abcabcabcabcabcabcabcabcabcabc
--- PASS: TestRepeat (0.00s)
PASSReplace String
s is the source string, old refers to the part to be replaced, new refers to the replacement part for old, and n refers to the number of replacements. When n is less than 0, it means unlimited replacements.
func Replace(s, old, new string, n int) stringExample:
func TestReplace(t *testing.T) {
fmt.Println(strings.Replace("Hello this is golang", "golang", "c++", 1))
fmt.Println(strings.Replace("Hello this is golang", "o", "c", -1))
fmt.Println(strings.Replace("Hello this is golang", "o", "c", 1))
}Output:
=== RUN TestReplace
Hello this is c++
Hellc this is gclang
Hellc this is golang
--- PASS: TestReplace (0.00s)
PASSConvenience function for Replace, equivalent to strings.Replace(s, old, new, -1):
func ReplaceAll(s, old, new string) stringExample:
func TestReplaceAll(t *testing.T) {
fmt.Println(strings.ReplaceAll("Hello this is golang", "o", "c++"))
}Output:
=== RUN TestReplaceAll
Hellc++ this is gc++lang
--- PASS: TestReplaceAll (0.00s)
PASSSplit String
Splits string s into a string slice according to substring sep:
func Split(s, sep string) []stringSplits string s into a string slice according to substring sep, with the number of splits determined by n:
func SplitN(s, sep string, n int) []stringSplits string s into a string slice containing sep as string elements:
func SplitAfter(s, sep string) []stringSplits string s into a string slice containing sep as string elements, with the number of splits determined by n:
func SplitAfterN(s, sep string, n int) []stringExample:
func TestSplit(t *testing.T) {
fmt.Printf("%q\n", strings.Split("this is go language", " "))
fmt.Printf("%q\n", strings.SplitN("this is go language", " ", 2))
fmt.Printf("%q\n", strings.SplitAfter("this is go language", " "))
fmt.Printf("%q\n", strings.SplitAfterN("this is go language", " ", 2))
}Output:
=== RUN TestSplit
["this" "is" "go" "language"]
["this" "is go language"]
["this " "is " "go " "language"]
["this " "is go language"]
--- PASS: TestSplit (0.00s)
PASSCase Conversion
Converts English string to lowercase:
func ToLower(s string) stringConverts to lowercase string according to the corresponding language's unicode.SpecialCase:
func ToLowerSpecial(c unicode.SpecialCase, s string) stringConverts English string to uppercase:
func ToUpper(s string) stringConverts to uppercase string according to the corresponding language's unicode.SpecialCase:
func ToUpperSpecial(c unicode.SpecialCase, s string) stringExample:
func TestLowerAndUpper(t *testing.T) {
fmt.Println(strings.ToLower("My name is jack,Nice to meet you!"))
fmt.Println(strings.ToLowerSpecial(unicode.TurkishCase, "Önnek İş"))
fmt.Println(strings.ToUpper("My name is jack,Nice to meet you!"))
fmt.Println(strings.ToUpperSpecial(unicode.TurkishCase, "örnek iş"))
}Output:
=== RUN TestLowerAndUpper
my name is jack,nice to meet you!
önnek iş
MY NAME IS JACK,NICE TO MEET YOU!
ÖRNEK İŞ
--- PASS: TestLowerAndUpper (0.00s)
PASSTrim String
Trims both ends of the string, removing any matching characters from cutset:
func Trim(s, cutset string) stringTrims the left end of the string, removing any matching characters from cutset:
func TrimLeft(s, cutset string) stringTrims the left prefix of the string, removing matching characters from cutset. If not matching, returns string s:
func TrimPrefix(s, suffix string) stringTrims the right end of the string, removing any matching characters from cutset:
func TrimRight(s, cutset string) stringTrims the right suffix of the string, removing matching characters from cutset. If not matching, returns string s:
func TrimSuffix(s, suffix string) stringExample:
func TestTrim(t *testing.T) {
fmt.Println(strings.Trim("!!this is a test statement!!", "!!!"))
fmt.Println(strings.TrimLeft("!!this is a test statement!!", "!!!"))
fmt.Println(strings.TrimRight("!!this is a test statement!!", "!!!"))
fmt.Println(strings.TrimPrefix("!!this is a test statement!!", "!!!"))
fmt.Println(strings.TrimSuffix("!!this is a test statement!!", "!!!"))
}Output:
=== RUN TestTrim
this is a test statement
this is a test statement!!
!!this is a test statement
!!this is a test statement!!
!!this is a test statement!!
--- PASS: TestTrim (0.00s)
PASSString Builder
String Builder is more memory-efficient than directly manipulating strings.
type Builder struct {
// Internal fields are not exposed
}Example:
func TestBuilder(t *testing.T) {
builder := strings.Builder{}
builder.WriteString("hello")
builder.WriteString(" world")
fmt.Println(builder.Len())
fmt.Println(builder.String())
}Output:
=== RUN TestBuilder
11
hello world
--- PASS: TestBuilder (0.00s)
PASSTIP
Do not attempt to pass Builder as a value, for example, when passing strings.Builder as a function parameter, the program will panic:
strings: illegal use of non-zero Builder copied by valueInternally, it has the following code:
type Builder struct {
addr *Builder // Address of itself
buf []byte
}
func (b *Builder) copyCheck() {
if b.addr == nil {
b.addr = (*Builder)(noescape(unsafe.Pointer(b)))
} else if b.addr != b {
panic("strings: illegal use of non-zero Builder copied by value")
}
}When copying a Builder by value, the pointer of the internal slice is also copied. Both Builders operate on the same slice when writing strings, which is why value copying is not allowed.
String Replacer
Replacer is used to replace strings:
func NewReplacer(oldnew ...string) *ReplacerExample:
func TestReplacer(t *testing.T) {
r := strings.NewReplacer("<", "<", ">", ">")
fmt.Println(r.Replace("This is <b>HTML</b>!"))
}Output:
This is <b>HTML</b>!String Reader
Reader implements io.Reader, io.ReaderAt, io.ByteReader, io.ByteScanner, io.RuneReader, io.RuneScanner, io.Seeker, and io.WriterTo interfaces.
func NewReader(s string) *ReaderExample:
func TestReader(t *testing.T) {
reader := strings.NewReader("abcdefghijk")
buffer := make([]byte, 20, 20)
read, err := reader.Read(buffer)
if err != nil {
log.Panic(err)
}
fmt.Println(read)
fmt.Println(string(buffer))
}Output:
=== RUN TestReader
11
abcdefghijk
--- PASS: TestReader (0.00s)
PASS