Golang strings标准库

1.1 字符串比较

//Compare函数用于比较两个字符串的大小,如果两个字符串相等,返回为0。如果a小于b,返回-1,反之返回1,不推荐使用,直接使用==,!=,<,>,<=,>=等一系列运算符更加直观。
func Compare(a,b string) int
//忽略大小写是否相等
func EquaFold(s,t string) bool

示例:

Compare

a := "gopher"
b := "hello "
fmt.Println(strings.Compare(a,b))
fmt.Println(strings.Compare(a,a))
fmt.Println(strings.Compare(b,a))

output:

-1
0
1

EqualFold

fmt.Println(strings.EqualFold("GO","go"))

output:

true

1.2 判断是否存在某个字符或子串

//子串substr在s中,返回true
func Contains(s,substr string) bool
//chars中任何一个Unicode代码点在s中,返回true
func Contains(s,chars string) bool
//Unicode代码点r在s中,返回true
func ContainsRune(s,string,r rune) bool

示例:

Contains

fmt.Println(strings.Contains("seafood", "foo"))
fmt.Println(strings.Contains("seafood", "bar"))
fmt.Println(strings.Contains("seafood", ""))
fmt.Println(strings.Contains("", ""))

Output:

true
false
true
true

ContainsAny

fmt.Println(strings.ContainsAny("team", "i"))
fmt.Println(strings.ContainsAny("fail", "ui"))
fmt.Println(strings.ContainsAny("ure", "ui"))
fmt.Println(strings.ContainsAny("failure", "ui"))
fmt.Println(strings.ContainsAny("foo", ""))
fmt.Println(strings.ContainsAny("", ""))

output:

false
true
true
true
false
false

ContainsRune

fmt.Println(strings.ContainsRune("aardvark", 97))
fmt.Println(strings.ContainsRune("timeout", 97))

Output:

true
false

查看三个函数的源码,只是调用了相应的Index函数(s中第一个substr实例的索引),然后与0作比较返回true或false。

func Contains(s, substr string) bool { 
    return Index(s, substr) >= 0 
}

1.3 子串出现的次数(字符串匹配)

在Go中,查找子串出现次数即字符串模式匹配,实现的是Rabin-Karp算法。

func Count(s, substr string) int

Count中,处理几种特殊情况,属于字符串匹配预处理的一部分,当子串substr为空时,Count的返回值utf8.RuneCountInString(s) + 1.

Count是计算子串在字符串中出现的无重叠的次数

示例:

Count

fmt.Println(strings.Count("cheese", "e"))
fmt.Println(strings.Count("five", "")) // before & after each rune
fmt.Println(strings.Count("banana","ana"))

output:

3
5
1

1.4 字符串分割

六个分割函数:Fields和FieldFunc、Split和SplitAfter、SplitN和SplitAfterN。

Fields和FieldFunc

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

Fields用一个或多个连续的空格分割字符串s,返回子字符串切片或空切片(slice)。如果字符串s只包含列表([]string的长度为0)。其中,空格的定义是unicode.IsSpace,常见的间隔符包含:\t,\n,\v,\f,\r,' ',U+0085 (NEL), U+00A0 (NBSP)

示例:

Fields

由于是空格分割,结果中不会含有空格或空字符串

fmt.Printf("Fields are: %q", strings.Fields(" 11 22 33 "))

output:

Fields are:["11","22","33"]

FieldsFunc

用Unicode代码点c进行分割:满足f(c)返回true,该函数返回[]string。如果字符串s中所有的代码点都满足f(c)或者s是空,则FieldsFunc返回空slice。

也就是说,可以通过实现一个回调函数来指定分割字符串s的字符。

示例:

fmt.Println(strings.FieldsFunc(" foo bar baz ", unicode.IsSpace))

output:

[foo bar baz]

实际上,Fields函数调用的FieldsFunc实现的:

func Fields(s string) []string { 
    return FieldsFunc(s, unicode.IsSpace) 
}

Split和SplitAfter、SplitN和SplitAfterN

func Split(s, sep string) []string
func SplitAfter(s, sep string) []string
func SplitAfterN(s, sep string, n int) []string
func SplitN(s, sep string, n int) []string

这四个函数都是通过一个内部函数genSplit来实现,通过sep进行分割,返回[]string。如果sep为空,相当于分成一个个UTF-8字符,如Split("abc",""),结果是["a","b","c"]。

Split(s,sep)和SplitN(s,sep,-1)等价;SplitN和SplitAfterN(s,sep,-1)等价。

示例:

Split和SplitAfter区别

fmt.Printf("%q\n", strings.Split("foo,bar,baz", ",")) 
fmt.Printf("%q\n", strings.SplitAfter("foo,bar,baz", ","))

output:

["foo" "bar" "baz"]
["foo," "bar," "baz"]

Split会将s中sep去掉,而SplitAfter会保留sep。

带N的方法可以通过最后一个参数n控制返回的结果中的slice中的元素个数,当n<0时,返回所有的子字符串,当n==0时,返回的结果是nil;当n>0时,表示返回slice中最多只有n个元素,其中,最后一个元素不会分割

例:

fmt.Printf("%q\n",strings.SplitN("foo,bar,baz",",",2))

output:

["foo","bar,baz"]

1.5 判断字符串前缀与后缀

// s中是否以prefix开始
func HasPrefix(s, prefix string) bool {
	return len(s) >= len(prefix) && s[0:len(prefix)] == prefix
}

// s中是否以suffix结尾
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", ""))
fmt.Println(strings.HasSuffix("Amigo", "go"))
fmt.Println(strings.HasSuffix("Amigo", "O"))
fmt.Println(strings.HasSuffix("Amigo", "Ami"))
fmt.Println(strings.HasSuffix("Amigo", ""))

output:

true
false
true
true
false
false
true

1.6字符串中字符或子串出现的位置

// 在s中查找sep的第一次出现的索引位置
func Index(s, sep string) int
// 在s中查找字节c的第一次出现,返回第一次出现的索引位置
func IndexByte(s string,c byte) int
// chars 中任何一个Unicode代码点在s中首次出现的位置
func IndexAny(s, chars string) int
// 查找字符c在s中第一次出现的位置,其中c满足f(c)返回true
func IndexFunc(s string,r rune) int
// Unicode代码点r在s中第一次出现的位置
func IndexRune(s string,r rune) int
// 返回s中substr最后一个实例的索引
func LastIndex(s substr string) int
// 返回最后一次出现的位置
func LastIndexByte(s sep string) int
func LastIndexAny(s, chars string) int
func LastIndexFunc(s string,f func(rune) bool) int

前面1.2中提到的Contain 相关的函数内部调用相应的Index 函数

示例:

IndexFunc

han:= func(c rune) bool {
    return unicode.Is(unicode.Han,c)	//汉字
}

fmt.Println(strings.IndexFunc("Hello, world",han))
fmt.Println(strings.IndexFunc("Hello, 世界",han))

output:
-1
7

1.6 字符串Join操作

讲字符串数组或slice连接起来可以通过Join实现:

func Join(elems []string, sep string) string

自己实现一个Join方法

func Join(str []string, sep string) string {
	if len(str) == 0 {
		return ""
	}
	if len(str) == 1 {
		return str[0]
	}
	buffer := bytes.NewBufferString(str[0])
	for _, s := range str[1:] {
		buffer.WriteString(sep)
		buffer.WriteString(s)
	}
	return buffer.String()
}

这里使用了bytes包的Buffer类型,避免大量的字符串连接操作,(因为Go中字符串是不可变)。

源码的实现:

func Join(a []string, sep string) string {
	if len(a) == 0 {
		return ""
	}
	if len(a) == 1 {
		return a[0]
	}
	n := len(sep) * (len(a) - 1)
	for i := 0; i < len(a); i++ {
		n += len(a[i])
	}

	b := make([]byte, n)
	bp := copy(b, a[0])
	for _, s := range a[1:] {
		bp += copy(b[bp:], sep)
		bp += copy(b[bp:], s)
	}
	return string(b)
}

源码实现没有使用bytes包,bytes中实现也是copy的方式

示例:

fmt.Println(strings.Join([]string{"foo", "bar", "baz"}, ", "))

output:
foo, bar, baz

1.7 字符串重复操作

func Repeat(s string, count int) string

将s重复count次,如果count为负数或返回值长度len(s)*count超出string上限会导致panic。

fmt.Println("ba" + strings.Repeat("na", 2))

Output:

banana

1.8 字符替换

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

Map函数将s的每一个字符按照mapping的规则做映射替换,如果mapping返回值<0,则舍弃该字符。该方法只能对每一个字符做处理,但处理方式很灵活,可以方便的过滤,筛选汉字等。

示例:

mapping := func(r rune) rune {
    switch {
        case r >= 'A' && r <= 'Z': //大写转小写
        return r+32
        case r >= 'a' && r <= 'z': //小写不处理
        return r
        case unicode.Is(unicode.Han, r): //汉字换行
        return '\n'
    }
    return -1	//过滤所有非字母,汉字的字符
}
fmt.Println(strings.Map(mapping, "abcd阀%……&*()Efg()H(i234j"))

Output:
abcd
efghij

1.9 字符串子串替换

进行字符串替换时,考虑到性能问题,能不用正则尽量别用,用这里的函数

// 用new替换s中的old,一共替换n个,如果n<0,则不限制替换次数,则全部替换。
func Replace(s, old, new string, n int) string
// 该函数内部直接调用函数Replace(s,old,new,-1)
func ReplaceAll(s, old, new string) string

示例:

fmt.Println(strings.Replace("oink oink oink", "k", "ky", 2))
fmt.Println(strings.Replace("oink oink oink", "oink", "moo", -1))
fmt.Println(strings.ReplaceAll("oink oink oink", "oink", "moo"))

Output:

oinky oinky oink
moo moo moo
moo moo moo

如果想一次性替换多个,例This is <b>HTML</b> 中的<,>为&lt ;,&gt ;使用1.13 Replacer进行操作

1.10 大小写转换

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

ToLower,ToUpper用于大小写转换,ToLowerSpecial,ToUpperSpecial用于转换特殊字符的大小写。

示例:

fmt.Println(strings.ToLower("Gopher"))
fmt.Println(strings.ToLowerSpecial(unicode.TurkishCase, "Önnek İş"))
fmt.Println(strings.ToUpper("Gopher"))
fmt.Println(strings.ToUpperSpecial(unicode.TurkishCase, "örnek iş"))

Output:

gopher
önnek iş
GOPHER
ÖRNEK İŞ

1.11 标题处理

//将s每个单词的首字母大写,不处理该单词后续字符
func Title(s string) string
//将s的每个字母大写
func ToTitle(s string) string
//将s的每个字母大写,并且将一些特殊的字母转换为其对应的特殊大写字母
func ToTitleSpecial(c unicode.SpecialCase, s string) string

示例:

fmt.Println(strings.Title("hElLo wOrLd"))
fmt.Println(strings.ToTitle("hElLo wOrLd"))
fmt.Println(strings.ToTitleSpecial(unicode.TurkishCase, "hElLo wOrLd"))
fmt.Println(strings.Title("āáǎà ōóǒò êēéěè"))
fmt.Println(strings.ToTitle("āáǎà ōóǒò êēéěè"))
fmt.Println(strings.ToTitleSpecial(unicode.TurkishCase, "āáǎà ōóǒò êēéěè"))
fmt.Println(strings.Title("dünyanın ilk borsa yapısı Aizonai kabul edilir"))
fmt.Println(strings.ToTitle("dünyanın ilk borsa yapısı Aizonai kabul edilir"))
fmt.Println(strings.ToTitleSpecial(unicode.TurkishCase, "dünyanın ilk borsa yapısı Aizonai kabul edilir"))


Output:

HElLo WOrLd
HELLO WORLD
HELLO WORLD
Āáǎà Ōóǒò Êēéěè
ĀÁǍÀ ŌÓǑÒ ÊĒÉĚÈ
ĀÁǍÀ ŌÓǑÒ ÊĒÉĚÈ
Dünyanın Ilk Borsa Yapısı Aizonai Kabul Edilir
DÜNYANIN ILK BORSA YAPISI AIZONAI KABUL EDILIR
DÜNYANIN İLK BORSA YAPISI AİZONAİ KABUL EDİLİR

1.12 修剪

// 将s两侧中匹配cutset中的任一字符去掉
func Trim(s string,cutset string) string
// 将s左侧的匹配cutset中的任一字符去掉
func TrimLeft(s string,cutset string) string
// 将s右侧的匹配cutset中的任一字符去掉
func TrimRight(s string,cutset string) string
// 去掉前缀prefix,如果不以prefix开头,返回s不变
func TrimPrefix(s,prefix string) string
// 去掉后缀suffix,如果不以suffix,返回s不变
func TrimSuffix(s,prefix string) string
// 去除s中前缀和后缀的间隔符。常见的有\t,\n,\v,\f,\r,' ', U+0085 (NEL)
func TrimSpace(s string) string
//去掉满足f(c)的前缀和后缀的unicode代码点
func TrimFunc(s string, f func(rune) bool ) string
//去掉满足f(c)的前缀的unicode代码点
func TrimLeftFunc(s string , f func( rune ) bool ) string
//去掉满足f(c)的后缀的unicode代码点
func TrimRightFunc(s string , f func( rune ) bool ) string

示例:

x := "!!!@@@你好,!@#$ Gophers###$$$"
fmt.Println(strings.Trim(x, "@#$!%^&*()_+=-"))
fmt.Println(strings.TrimLeft(x, "@#$!%^&*()_+=-"))
fmt.Println(strings.TrimRight(x, "@#$!%^&*()_+=-"))
fmt.Println(strings.TrimSpace(" \t\n Hello, Gophers \n\t\r\n"))
fmt.Println(strings.TrimPrefix(x, "!"))
fmt.Println(strings.TrimSuffix(x, "$"))
f := func(r rune) bool {
    return !unicode.Is(unicode.Han, r) // 非汉字返回 true
}
fmt.Println(strings.TrimFunc(x, f))
fmt.Println(strings.TrimLeftFunc(x, f))
fmt.Println(strings.TrimRightFunc(x, f))

Output:

你好,!@#$ Gophers
你好,!@#$ Gophers###$$$
!!!@@@你好,!@#$ Gophers
Hello, Gophers
!!@@@你好,!@#$ Gophers###$$$
!!!@@@你好,!@#$ Gophers###$$
你好
你好,!@#$ Gophers###$$$
!!!@@@你好

1.13 Replacer类型

func NewReplacer(oldnew ...string) *Replacer

其中不定参数oldnew是old-new,即进行多个替换。如果oldnew参数是一个,会导致panic.

示例:

r := strings.NewReplacer("<", "&lt;", ">", "&gt;")
fmt.Println(r.Replace("This is <b>HTML</b>!"))

Output:

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

另外,Replacer 还提供了另外一个方法,它在执行所有替换的情况下将s写入w。

func (r *Replacer) WriteString(w io.Writer, s string) (n int, err error)

1.14 Reader类型

这是实现了io包中的接口。它实现了

io.Reader(Read方法),

io.ReaderAt(ReadAt方法),

io.Seeker(Seek方法),

io.WriterTo(WriteTo方法),

io.ByteReader(ReadByte方法),

io.ByteScanner(ReadByte和UnreadByte方法),

io.RuneReader(ReadRune方法)

io.RuneScanner(ReadRune和UnreadRune方法)。

Reader结构体:

type Reader struct { 
    s string // Reader 读取的数据来源 
    i int // current reading index(当前读取的数据索引位置) 
    prevRune int // index of previous rune; or < 0(前一个读取的 rune 索引位置) 
}

Reader提供了一个实例化方法:

func NewReader(s string) *Reader

该方法接受一个字符串,返回的Reader实例就是从该参数字符串读数据,bytes.NewBufferString有类似的功能,不过,如果只是为了读取,NewReader会更高效

1.15 Builder类型

type Builder struct {
	addr *Builder // of receiver, to detect copies by value
	buf  []byte
}

该类型实现了io包下的Write,ByteWrite,WriteString等接口,可以向该对象内写入数据,Builder没有实现Reader等接口,所以该类型不可读,但提供了String方法可以获取对象内的数据。

//该方法向b写入一个字节
func(b*Builder)WriteByte(cbyte)error
//WriteRune方法向b写入一个字符
func(b*Builder)WriteRune(rrune)(int,error)
//WriteRune方法向b写入字节数组p
func(b*Builder)Write(p[]byte)(int,error)
//WriteRune方法向b写入字符串s
func(b*Builder)WriteString(sstring)(int,error)
//Len方法返回b的数据长度。
func(b*Builder)Len()int
//Cap方法返回b的cap。
func(b*Builder)Cap()int
//Grow方法将b的cap至少增加n(可能会更多)。如果n为负数,会导致panic。func(b*Builder)Grow(nint)
//Reset方法将b清空b的所有内容。
func(b*Builder)Reset()
//String方法将b的数据以string类型返回。
func(b*Builder)String()string

Builder 有 4 个与写入相关的方法,这 4 个方法的 error 都总是为 nil.

Builder 的 cap 会自动增长,一般不需要手动调用 Grow 方法

String 方法可以方便的获取 Builder 的内容。

示例:

b:=strings.Builder{}
_=b.WriteByte('7')
n,_:=b.WriteRune('夕')
fmt.Println(n)
n,_=b.Write([]byte("Hello,World"))
fmt.Println(n)
n,_=b.WriteString("你好,世界")
fmt.Println(n)
fmt.Println(b.Len())
fmt.Println(b.Cap())
b.Grow(100)
fmt.Println(b.Len())
fmt.Println(b.Cap())
fmt.Println(b.String())
b.Reset()
fmt.Println(b.String())

Output:

3
11
15
30
32
30
164
7夕Hello,World你好,世界
posted @ 2021-10-19 20:38  自己有自己的调调、  阅读(386)  评论(0编辑  收藏  举报