Go标准库学习:strings和bytes
strings包和bytes包
strings
包和bytes
包非常像,几乎所有函数都有string
和[]byte
两种接口,其中前者被实现在strings
包中,而后者被是现在bytes
包中,所以这里将这两个包一起学习。
官方文档:
strings包:https://pkg.go.dev/strings@go1.21.4
bytes包:https://pkg.go.dev/bytes@go1.21.4
函数
clone
// strings func Clone(s string) string // bytes func Clone(b []byte) []byte
克隆[]byte和string。默认赋值操作只是浅拷贝,Clone会对[]byte和string进行深拷贝。
func CloneTest() { sliceCopyTest() sliceCloneTest() stringCopyTest() stringCloneTest() } func sliceCopyTest() { bts01 := []byte("testing") bts02 := bts01 fmt.Print("Copy(bts02 := bts01), ") bts01[0] = 's' fmt.Println("bts01[0] = 's':") fmt.Printf("bts01 = %q, bts02 = %q\n", bts01, bts02) fmt.Println() } func sliceCloneTest() { bts01 := []byte("testing") bts02 := bytes.Clone(bts01) fmt.Print("Copy(bts02 := bytes.Clone(bts01)), ") bts01[0] = 's' fmt.Println("bts01[0] = 's':") fmt.Printf("bts01 = %q, bts02 = %q\n", bts01, bts02) fmt.Println() } func stringCopyTest() { str01 := "testing" str02 := str01 fmt.Println("str02 := str01:") fmt.Printf("unsafe.StringData(str01) == unsafe.StringData(str02): %v\n", unsafe.StringData(str01) == unsafe.StringData(str02)) fmt.Println() } func stringCloneTest() { str01 := "testing" str02 := strings.Clone(str01) fmt.Println("str02 := strings(str01):") fmt.Printf("unsafe.StringData(str01) == unsafe.StringData(str02): %v\n", unsafe.StringData(str01) == unsafe.StringData(str02)) fmt.Println() } /* Output: Copy(bts02 := bts01), bts01[0] = 's': bts01 = "sesting", bts02 = "sesting" Copy(bts02 := bytes.Clone(bts01)), bts01[0] = 's': bts01 = "sesting", bts02 = "testing" str02 := str01: unsafe.StringData(str01) == unsafe.StringData(str02): true str02 := strings(str01): unsafe.StringData(str01) == unsafe.StringData(str02): false */
内容检查类的函数,是否包含。Contains/Has.
// strings // s中是否包含substr func Contains(s, substr string) bool // s中是否包含r func ContainsRune(s string, r rune) bool // s中是否包含任何chars中的rune func ContainsAny(s, chars string) bool // 对s中的所有rune调用f,是否有一个调用结果为true func ContainsFunc(s string, f func(rune) bool) bool // s中是否有前缀prefix func HasPrefix(s, prefix string) bool // s中是否有后缀suffix func HasSuffix(s, suffix string) bool // bytes func Contains(b, subslice []byte) bool func ContainsRune(b []byte, r rune) bool func ContainsAny(b []byte, chars string) bool // 注意,chars类型为string func ContainsFunc(b []byte, f func(rune) bool) bool func HasPrefix(s, prefix []byte) bool func HasSuffix(s, suffix []byte) bool
测试:
func ContainsAndHasTest() { str01 := "“你好”是一个很好的词汇" fmt.Println(strings.Contains(str01, "词汇")) // true fmt.Println(strings.ContainsAny(str01, "词语")) // true fmt.Println(strings.ContainsRune(str01, '你')) // true fmt.Println(strings.ContainsFunc(str01, func(r rune) bool { return r == '你' || r == '我' })) // true fmt.Println(strings.HasPrefix(str01, "“你好")) // true fmt.Println(strings.HasSuffix(str01, "词汇")) // true fmt.Println() }
Count
// strings func Count(s, substr string) int // bytes func Count(s, sep []byte) int
获取字串在s中的数量,字串为空串则返回1 + s中unicode码点的数量
获取字串的下标 Index
// strings // 字串在s中的下标(in byte) func Index(s, substr string) int // unicode码点r在s中的第一个下标,r不是一个合法的码点则返回第一个非法码点的下标 func IndexRune(s string, r rune) int // 字节c在s中的第一个下标 func IndexByte(s string, c byte) int // chars中任意一个rune出现在s中的第一个下标 func IndexAny(s, chars string) int // s中的rune r,使得f(r)为真的第一个rune的下标 func IndexFunc(s string, f func(rune) bool) int // 最后一个下标的版本,注意,没有IndexLastRune这个函数 func LastIndex(s, substr string) int func LastIndexAny(s, chars string) int func LastIndexByte(s string, c byte) int func LastIndexFunc(s string, f func(rune) bool) int // bytes func Index(s, sep []byte) int func IndexAny(s []byte, chars string) int func IndexByte(b []byte, c byte) int func IndexFunc(s []byte, f func(r rune) bool) int func IndexRune(s []byte, r rune) int func LastIndex(s, sep []byte) int func LastIndexAny(s []byte, chars string) int func LastIndexByte(s []byte, c byte) int func LastIndexFunc(s []byte, f func(r rune) bool) int
获取string/[]byte中rune/byte/string/[]byte的下标/最后一个下标的函数
func IndexTest() { str01 := "你好你好你呀" str02 := "好你" fmt.Printf("Index(%q, %q) = %d\n", str01, str02, strings.Index(str01, str02)) fmt.Printf("IndexByte(%q, %q) = %d\n", str01, str02[0], strings.IndexByte(str01, str02[0])) r, _ := utf8.DecodeRuneInString(str02) fmt.Printf("IndexRune(%q, %q) = %d\n", str01, r, strings.IndexRune(str01, r)) fmt.Printf("IndexAny(%q, %q) = %d\n", str01, str02, strings.IndexAny(str01, str02)) isNi := func(r rune) bool { return r == '你' } fmt.Printf("IndexFunc(%q, isNi) = %d\n", str01, strings.IndexFunc(str01, isNi)) fmt.Printf("LastIndex(%q, %q) = %d\n", str01, str02, strings.LastIndex(str01, str02)) fmt.Printf("LastIndexByte(%q, %q) = %d\n", str01, str02[0], strings.LastIndexByte(str01, str02[0])) // fmt.Printf("LastIndexRune(%q, %q) = %d\n", str01, r, strings.LastIndexRune(str01, r)) // No Such Function fmt.Printf("LastIndexAny(%q, %q) = %d\n", str01, str02, strings.LastIndexAny(str01, str02)) fmt.Printf("LastIndexFunc(%q, isNi) = %d\n", str01, strings.LastIndexFunc(str01, isNi)) } /* Output: Index("你好你好你呀", "好你") = 3 IndexByte("你好你好你呀", 'å') = 3 IndexRune("你好你好你呀", '好') = 3 IndexAny("你好你好你呀", "好你") = 0 IndexFunc("你好你好你呀", isNi) = 0 LastIndex("你好你好你呀", "好你") = 9 LastIndexByte("你好你好你呀", 'å') = 15 LastIndexAny("你好你好你呀", "好你") = 12 LastIndexFunc("你好你好你呀", isNi) = 12 */
相等性测试
// strings // string的相等性测试可以直接使用 == 操作符 // 在unicode字符集中忽略大小写进行比较,更加通用 func EqualFold(s, t string) bool // bytes // a和b是否长度相同且内容相同 func Equal(a, b []byte) bool func EqualFold(s, t []byte) bool
Equal是相等性测试,EqualFold是忽略大小写的相等性测试。
// 用泛型实现Equal func Equal[T comparable](a, b []T) bool { if len(a) != len(b) { return false } for i := 0; i < len(a); i++ { if a[i] != b[i] { return false } } return true } func EqualTest() { strSlice := []string{"abc", "def", "你好"} strSlice2 := []string{"abc", "def", "你好"} byteSlice := []byte{1, 2, 3, 4, 5} byteSlice2 := []byte{1, 2, 3, 4, 5} fmt.Printf("Equal(%q, %q) = %v\n", strSlice, strSlice2, Equal(strSlice, strSlice2)) fmt.Printf("Equal(%q, %q) = %v\n", byteSlice, byteSlice2, Equal(byteSlice, byteSlice2)) } /* Output: Equal(["abc" "def" "你好"], ["abc" "def" "你好"]) = true Equal("\x01\x02\x03\x04\x05", "\x01\x02\x03\x04\x05") = true */
去掉前缀、后缀,分割等函数
// strings // 按照sep,将s分割为 before、sep、after,如果sep在s中不存在,返回s, "", false func Cut(s, sep string) (before, after string, found bool) // 如果prefix是s的前缀,返回s[len(prefix):],true,s中没有prefix则返回s,false,prefix为空则返回s,true func CutPrefix(s, prefix string) (after string, found bool) // 剪除后缀 func CutSuffix(s, suffix string) (before string, found bool) // 按照sep将s分割 // If s does not contain sep and sep is not empty, Split returns a slice of length 1 whose only element is s. // If sep is empty, Split splits after each UTF-8 sequence. // If both s and sep are empty, Split returns an empty slice. func Split(s, sep string) []string // 最多划分为n个substring // n > 0: at most n substrings; the last substring will be the unsplit remainder. // n == 0: the result is nil (zero substrings) // n < 0: all substrings func SplitN(s, sep string, n int) []string // sep不会被丢弃,而是放在被分割的字串后面 func SplitAfter(s, sep string) []string // 最多划分为n个字串 func SplitAfterN(s, sep string, n int) []string // 按照空白字符将s分割为slice,空白字符的判断标准为unicode.IsSpace() func Fields(s string) []string // 按照f(r)的结果将s分割为slice,Fields等效于FieldsFunc(s, unicode.IsSpace) func FieldsFunc(s string, f func(rune) bool) []string // 从前面和后面删除连续的cutset中的unicode码点,然后返回s的slice func Trim(s, cutset string) string // 从前面和后面删除连续的空白字符,相等于TrimFunc(s, unicode.isSpace) func TrimSpace(s string) string // 从s前面和后面删除连续的使得f(r)为真的unicode码点,然后返回s的slice func TrimFunc(s string, f func(rune) bool) string // 从s前面删除连续的cutset中的unicode码点,然后返回s的slice func TrimLeft(s, cutset string) string // 从s后面删除连续的cutset中的unicode码点,然后返回s的slice func TrimRight(s, cutset string) string // 从s前面删除连续的使得f(r)为真的unicode码点,然后返回s的slice func TrimLeftFunc(s string, f func(rune) bool) string // 从s前面删除连续的使得f(r)为真的unicode码点,然后返回s的slice func TrimRightFunc(s string, f func(rune) bool) string // 如果s的前缀是prefix,则删除该前缀,返回s的slice;否则返回s func TrimPrefix(s, prefix string) string // 如果s的后缀是suffix,则删除该后缀,返回s的slice,否则返回s func TrimSuffix(s, suffix string) string // bytes func Cut(s, sep []byte) (before, after []byte, found bool) func CutPrefix(s, prefix []byte) (after []byte, found bool) func CutSuffix(s, suffix []byte) (before []byte, found bool) func Split(s, sep []byte) [][]byte func SplitAfter(s, sep []byte) [][]byte func SplitAfterN(s, sep []byte, n int) [][]byte func SplitN(s, sep []byte, n int) [][]byte func Fields(s []byte) [][]byte func FieldsFunc(s []byte, f func(rune) bool) [][]byte func Trim(s []byte, cutset string) []byte func TrimFunc(s []byte, f func(r rune) bool) []byte func TrimLeft(s []byte, cutset string) []byte func TrimLeftFunc(s []byte, f func(r rune) bool) []byte func TrimPrefix(s, prefix []byte) []byte func TrimRight(s []byte, cutset string) []byte func TrimRightFunc(s []byte, f func(r rune) bool) []byte func TrimSpace(s []byte) []byte func TrimSuffix(s, suffix []byte) []byte
重复字符串
// strings // 返回count个s首尾相连组成的字符串,count < 0是出错 func Repeat(s string, count int) string // bytes func Repeat(b []byte, count int) []byte
单纯的将s重复几次
替换字符串/转换字符串
// strings // 将s中的每个字符使用mapping函数替换,返回拷贝。如果mapping函数返回一个负值,函数会丢弃该字符 func Map(mapping func(rune) rune, s string) string // 将s中n个不重叠的old字符串替换为new字符串,n < 0时替换所有字符串 // old为空时在每个unicode码点之间(包括最开始和最后)添加new对应的字符串,最多替换n个 func Replace(s, old, new string, n int) string // 等于Replace(s, old, new, -1) func ReplaceAll(s, old, new string) string // 将s中的unicode码点转化为小写 func ToLower(s string) string // 部分语言有特殊的大小写映射,ToLowerSprcial方法优先处理这些特殊的大小写映射 func ToLowerSpecial(c unicode.SpecialCase, s string) string // 将s中的unicode码点转化为标题格式,目前来看英文转化为全大写,中文不变 func ToTitle(s string) string // 部分语言有特殊的标题格式映射 func ToTitleSpecial(c unicode.SpecialCase, s string) string // 转化为大写 func ToUpper(s string) string // 部分语言有特殊的大小写映射 func ToUpperSpecial(c unicode.SpecialCase, s string) string // 将s中非法的utf8字节序列替换为replacement func ToValidUTF8(s, replacement string) string // bytes func Map(mapping func(r rune) rune, s []byte) []byte func Replace(s, old, new []byte, n int) []byte func ReplaceAll(s, old, new []byte) []byte // 将s中的字节解读为unicode码点 func Runes(s []byte) []rune func ToLower(s []byte) []byte func ToLowerSpecial(c unicode.SpecialCase, s []byte) []byte func ToTitle(s []byte) []byte func ToTitleSpecial(c unicode.SpecialCase, s []byte) []byte func ToUpper(s []byte) []byte func ToUpperSpecial(c unicode.SpecialCase, s []byte) []byte func ToValidUTF8(s, replacement []byte) []byte
这部分是关于字符串/[]byte的替换/转换的函数,针对的都是字符串,针对单个unicode码点(rune类型)的操作(比如IsUpper, IsSpace, ToUpper)在unicode
库中。
类型(type)
用于构建string的类
因为string是不可变类型,在用+操作符构建string时每一次都要分配一次内存,导致效率低下。
所以go标准库提供了高效构建string的类。
Builder类
// strings type Builder struct { // contains filtered or unexported fields }
Builder类型是strings包提供的,用于高效构建string的类,其会最小化内存拷贝。
不要拷贝非零的Builder对象。
Builder类的成员方法
func (b *Builder) Len() int
builder已经写入的字节数;b.Len() = len(b.String())
func (b *Builder) Cap() int
获取该builder已经分配的,用于构建string的空间,包括已经写入的空间。
func (b *Builder) Grow(n int)
增长builder的容量,使其至少能再写入n个字节,而不用再次分配内存。
func (b *Builder) Reset()
清空builder已经写入的内容
func (b *Builder) String() string
返回累加的string
func (b *Builder) Write(p []byte) (int, error) func (b *Builder) WriteByte(c byte) error func (b *Builder) WriteRune(r rune) (int, error) func (b *Builder) WriteString(s string) (int, error)
向builder中写入内容。
Buffer类
type Buffer struct { // contains filtered or unexported fields }
Buffer是bytes包提供的高效的string构建类,其比Builder更加强大。Builder的读出操作只有String()方法,Buffer支持更多的读出方法。
与Buffer类相关的函数
func NewBuffer(buf []byte) *Buffer func NewBufferString(s string) *Buffer
分别以[]byte和string的内容为基础构建新的Buffer类实例。
大多数情况下,new(Buffer)
(或者直接定义一个Buffer类型的变脸)就可以初始化一个空的Buffer。
Buffer类的成员方法
func (b *Buffer) Available() int func (b *Buffer) Cap() int func (b *Buffer) Len() int
空间大小相关的函数。
Cap()
返回Buffer的内部空间的容量。
Available()
返回还未使用的,但已经申请的空间的大小。
Len()
返回写入后未读出的空间的大小。
func (b *Buffer) Grow(n int)
使得Buffer至少能再读入n个字节而不重新分配内存。
func (b *Buffer) Truncate(n int)
除了前n个未读的字节外,丢弃其他已写入的字节,不会重新分配内存。
func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error) func (b *Buffer) Write(p []byte) (n int, err error) func (b *Buffer) WriteByte(c byte) error func (b *Buffer) WriteRune(r rune) (n int, err error) func (b *Buffer) WriteString(s string) (n int, err error)
向Buffer中写入内容。
与strings.Builder
不同的是有一个ReadFrom()
方法,该方法从一个io.Reader
(这是一个接口,包含Read()
方法)中读取内容,并返回读取的字节数量和出现的错误(io.EOF
不视为错误,io.Reader
的Read()
方法返回io.EOF
时ReadFrom()
方法不会返回错误)。
func (b *Buffer) Bytes() []byte func (b *Buffer) Read(p []byte) (n int, err error) func (b *Buffer) ReadByte() (byte, error) func (b *Buffer) ReadBytes(delim byte) (line []byte, err error) func (b *Buffer) ReadRune() (r rune, size int, err error) func (b *Buffer) ReadString(delim byte) (line string, err error) func (b *Buffer) String() string func (b *Buffer) WriteTo(w io.Writer) (n int64, err error)
Buffer类中有众多的读出方式,包括读取全部字节、读指定数量的字节、读一个字节、读到某个字节为止、读一个unicode码点、全部都出来作为一个string
。
同时Buffer类还有一个与ReadFrom()
对应的方法WriteTo()
,该方法将字节写入到一个io.Writer
(这是一个接口,包含Write()
方法)中,并返回写入的字节数和出现的错误。
func (b *Buffer) AvailableBuffer() []byte
返回未写入的空闲的空间,直到下次写入操作前该空间都有效。
func (b *Buffer) UnreadByte() error func (b *Buffer) UnreadRune() error
将上次读取的byte/rune回退到缓冲区中。
用于读取string/[]byte的类
有时候我们需要将string
/[]byte
当作输入,strings和bytes包中都提供了名为Reader
的类,用于将string
/[]byte
作为输入源。
strings.Reader
type Reader struct { // contains filtered or unexported fields }
实现了io.Reader, io.ReaderAt, io.ByteReader, io.ByteScanner, io.RuneReader, io.RuneScanner, io.Seeker, io.WriterTo
接口,使用string
作为输入源,零值的行为与以空字符串初始化相同。
strings.Reader相关函数
func NewReader(s string) *Reader
以s
为输入源创建一个strings.Reader
。
成员函数
func (r *Reader) Len() int // 返回还未读出的字节的数量 func (r *Reader) Read(b []byte) (n int, err error) func (r *Reader) ReadAt(b []byte, off int64) (n int, err error) func (r *Reader) ReadByte() (byte, error) func (r *Reader) ReadRune() (ch rune, size int, err error) func (r *Reader) Reset(s string) // 重置,再次从头开始读 func (r *Reader) Seek(offset int64, whence int) (int64, error) // 重新定位到某个地方,实现了io.Seeker接口 func (r *Reader) Size() int64 // 返回字符串s的初始长度 func (r *Reader) UnreadByte() error func (r *Reader) UnreadRune() error func (r *Reader) WriteTo(w io.Writer) (n int64, err error)
大部分语义和前面的一样,没见过的加了注释。
bytes.Reader
type Reader struct { // contains filtered or unexported fields }
和strings.Reader
类似,只不过使用[]byte
作为输入源。
相关函数
func NewReader(b []byte) *Reader
成员函数
func (r *Reader) Len() int func (r *Reader) Read(b []byte) (n int, err error) func (r *Reader) ReadAt(b []byte, off int64) (n int, err error) func (r *Reader) ReadByte() (byte, error) func (r *Reader) ReadRune() (ch rune, size int, err error) func (r *Reader) Reset(b []byte) func (r *Reader) Seek(offset int64, whence int) (int64, error) func (r *Reader) Size() int64 func (r *Reader) UnreadByte() error func (r *Reader) UnreadRune() error func (r *Reader) WriteTo(w io.Writer) (n int64, err error)
strings.Replacer
type Replacer struct { // contains filtered or unexported fields }
用于方便地替换string中的内容的辅助类,看后面的例子就明白了。
相关函数
func NewReplacer(oldnew ...string) *Replacer
以old1, new1, old2, new2...的顺序构建Replacer,表示将后续的字符串中的所有的old1/old2/...替换为new1/new2/...
例子:
package main import ( "fmt" "strings" ) func main() { r := strings.NewReplacer("<", "<", ">", ">") fmt.Println(r.Replace("This is <b>HTML</b>!")) } // 官网示例,在我的go version go1.21.4 linux/amd64中没问题。 /* Output: This is <b>HTML</b>! */
成员函数
func (r *Replacer) Replace(s string) string
将s
按照预定义的规则替换,返回替换后的字符串。
func (r *Replacer) WriteString(w io.Writer, s string) (n int, err error)
将替换后的字符串写入w
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· 单线程的Redis速度为什么快?
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码