Skip to content

strings

strings 實現了簡單的函數來操作 UTF-8 編碼的字符串,簡單來說就是操作字符串的工具包。

官方文檔:strings package - strings - Go Packages

TIP

Go 天然支持 UTF8 字符,所有的字符串操作都是建立在 UTF8 的基礎之上。

導入

go
import (
   "strings"
)

下面將以示例的形式講解常用的函數。

復制字符串

go
func Clone(s string) string

將會分配一個新的內存給復制的副本,如果傳入一個空字符串,則不會分配內存且返回空字符串。

go
func TestClone(t *testing.T) {
   ori := "hello 世界"
   copys := strings.Clone(ori)
   fmt.Println(ori, copys)
   fmt.Println(&ori, &copys)
}
=== RUN   TestClone
hello 世界 hello 世界
0xc00005e5d0 0xc00005e5e0
--- PASS: TestClone (0.00s)
PASS

比較字符串

go
func Compare(a, b string) int

將 a 與 b 按照字典順序進行字符串比較,如果 a>b,返回 1,a<b 返回-1,a=b 返回 0。

go
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)
PASS

包含字符串

go
func Contains(s, substr string) bool

判斷一個字符串 s 是不是包含一個子串 substr

go
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)
PASS
go
func ContainsAny(s, chars string) bool

判斷字符串 chars 內任意字符的 unicode 碼是否在字符串 s 內,翻譯一下就是 s 是否包含 chars 內的任意字符串

go
func TestContainsAny(t *testing.T) {
  fmt.Println(strings.ContainsAny("abcedfg", "bac"))
  fmt.Println(strings.ContainsAny("abcedfg", "gfdecba"))
}
=== RUN   TestContainsAny
true
--- PASS: TestContainsAny (0.00s)
PASS
go
func ContainsRune(s string, r rune) bool

判斷字符串 s 內是否包含字符 r

go
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)
PASS

子串出現次數

go
func Count(s, substr string) int

給出子串 substr 在字符串 s 內的出現次數

go
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)
PASS

刪除指定子串

go
func Cut(s, sep string) (before, after string, found bool)

刪除在 s 內第一次出現的子串 sep,並返回刪除後的結果

  • before - 被刪除子串位置前面的字符串
  • after - 被刪除子串位置後面的字符串
  • found - 是否找到子串
go
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)
PASS

忽略大小寫相等

go
func EqualFold(s, t string) bool

返回字符串 s 和 t 在忽略大小寫情況下是否相等

go
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)
PASS

分割字符串

go
func Fields(s string) []string
go
func FieldsFunc(s string, f func(rune) bool) []string

前者是根據空格來分割字符串,後者是函數 f 的返回值來決定是否分割字符串。

go
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)
PASS

尋找前後綴

go
func HasPrefix(s, prefix string) bool
go
func HasSuffix(s, suffix string) bool

前者是尋找前綴,後者是尋找後綴,感興趣可以去看看這裡的源碼實現,比較巧妙。

go
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)
PASS

子串的位置

返回第一次出現的子串的下標

go
func Index(s, substr string) int

返回第一次出現的子串的下標

go
func IndexAny(s, chars string) int

返回第一次出現的子串的下標

go
func IndexRune(s string, r rune) int

示例

go
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)
PASS

返回最後一次出現的子串的下標

go
func LastIndex(s, substr string) int

返回最後一次出現的子串任意字符的下標

go
func LastIndexAny(s, chars string) int

示例

go
func TestLastIndex(t *testing.T) {
  fmt.Println(strings.LastIndex("abcdefga", "a"))
  fmt.Println(strings.LastIndexAny("abcdefghisa", "ba"))
}

遍歷替換字符串

Map 返回字符串 s 的副本,並根據映射函數修改字符串 s 的所有字符。如果映射返回負值,則從字符串中刪除該字符,不進行替換

go
func Map(mapping func(rune) rune, s string) string

示例

go
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"))
}

輸出

text
=== RUN   TestMap
ABCDEFGHIJK
abcdefghijk
FGHIJK
--- PASS: TestMap (0.00s)
PASS

重復復制字符串

根據給定的 Count 復制字符串,如果為負數會導致panic

go
func Repeat(s string, count int) string

示例

go
func TestRepeat(t *testing.T) {
   fmt.Println(strings.Repeat("a", 10))
   fmt.Println(strings.Repeat("abc", 10))
}

輸出

=== RUN   TestRepeat
aaaaaaaaaa
abcabcabcabcabcabcabcabcabcabc
--- PASS: TestRepeat (0.00s)
PASS

替換字符串

s 為源字符串,old 指要被替換的部分,new 指 old 的替換部分,n 指的是替換次數,n 小於 0 時表示不限制替換次數。

go
func Replace(s, old, new string, n int) string

示例

go
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))
}

輸出

=== RUN   TestReplace
Hello this is c++
Hellc this is gclang
Hellc this is golang
--- PASS: TestReplace (0.00s)
PASS

Replace的方便函數,等價於stings.Replace(s,old,new,-1)

go
func ReplaceAll(s, old, new string) string

示例

go
func TestReplaceAll(t *testing.T) {
  fmt.Println(strings.ReplaceAll("Hello this is golang", "o", "c++"))
}

輸出

=== RUN   TestReplaceAll
Hellc++ this is gc++lang
--- PASS: TestReplaceAll (0.00s)
PASS

分隔字符串

根據子串 sep 將字符串 s 分隔成一個字符串切片

go
func Split(s, sep string) []string

根據子串 sep 將字符串 s 分隔成一個字符串切片,其分隔次數由 n 決定

go
func SplitN(s, sep string, n int) []string

根據子串 sep 將字符串 s 分隔成包含 sep 的字符串元素組成的字符串切片

go
func SplitAfter(s, sep string) []string

根據子串 sep 將字符串 s 分隔成包含 sep 的字符串元素組成的字符串切片,其分隔次數由 n 決定

go
func SplitAfterN(s, sep string, n int) []string

示例

go
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))
}

輸出

=== RUN   TestSplit
["this" "is" "go" "language"]
["this" "is go language"]
["this " "is " "go " "language"]
["this " "is go language"]
--- PASS: TestSplit (0.00s)
PASS

大小寫轉換

將英文字符串英文小寫字符串

go
func ToLower(s string) string

根據傳入的對應語言的unicode.SpecialCase ,轉換成對應語言的小寫字符串

go
func ToLowerSpecial(c unicode.SpecialCase, s string) string

將英文字符串轉換成大寫字符串

go
func ToUpper(s string) string

根據傳入對應語言的unicode.SpecialCase,轉換成對應語言的大寫字符串

go
func ToUpperSpecial(c unicode.SpecialCase, s string) string

示例

go
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ş"))
}

輸出

=== 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)
PASS

修剪字符串

修剪字符串兩端,將 cutset 任意匹配的子串刪除

go
func Trim(s, cutset string) string

修剪字符串左端,將 cutset 任意匹配的子串刪除

go
func TrimLeft(s, cutset string) string

修剪字符串左端前綴,將 cutset 匹配的子串刪除,不匹配就會返回字符串 s

go
func TrimPrefix(s, suffix string) string

修剪字符串右端,將 cutset 任意匹配的子串刪除

go
func TrimRight(s, cutset string) string

修剪字符串右端後綴,將 cutset 匹配的子串刪除,不匹配就會返回字符串 s

go
func TrimSuffix(s, suffix string) string

示例

go
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!!", "!!!"))
}

輸出

=== 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)
PASS

字符串 Builder

字符串 Builder 比起直接操作字符串更加節省內存。

go
type Builder struct {
  // 內部字段不對外暴露
}

示例

go
func TestBuilder(t *testing.T) {
   builder := strings.Builder{}
   builder.WriteString("hello")
   builder.WriteString(" world")
   fmt.Println(builder.Len())
   fmt.Println(builder.String())
}

輸出

=== RUN   TestBuilder
11
hello world
--- PASS: TestBuilder (0.00s)
PASS

TIP

不要試圖將Builder作為值進行傳遞,例如將strings.Builder作為函數參數傳遞的時候,程序會panic

strings: illegal use of non-zero Builder copied by value

其內部有如下一段代碼

go
type Builder struct {
  addr *Builder //自身的地址
  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")
   }
}

當對Builder 進行值拷貝的同時,也拷貝了內部切片的指針,兩個Builder在寫入字符串的時候都是在對同一個切片進行操作,這也是為什麼不允許被值拷貝的原因。

字符串 Replacer

Replacer 轉用於替換字符串

go
func NewReplacer(oldnew ...string) *Replacer

示例

go
func TestReplacer(t *testing.T) {
  r := strings.NewReplacer("<", "&lt;", ">", "&gt;")
  fmt.Println(r.Replace("This is <b>HTML</b>!"))
}

輸出

This is &lt;b&gt;HTML&lt;/b&gt;!

字符串 Reader

Reader 實現了 io.Reader, io.ReaderAt, io.ByteReader, io.ByteScanner, io.RuneReader, io.RuneScanner, io.Seeker, 和 io.WriterTo interfaces。

go
func NewReader(s string) *Reader

示例

go
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))
}

輸出

=== RUN   TestReader
11
abcdefghijk
--- PASS: TestReader (0.00s)
PASS

Golang學習網由www.golangdev.cn整理維護