Golang标准库学习——strings(未完)

Package strings

import "strings"

strings包实现了用于操作字符串的简单函数

一、Contains、ContainsAny、ContainsRune

// 判断s是否包含substr
func Contains(s, substr string) bool {
	return Index(s, substr) >= 0
}

// 判断s是否包含r 
func ContainsAny(s, chars string) bool {
	return IndexAny(s, chars) >= 0
}

// 判断s是否包含chars的任一字符
func ContainsRune(s string, r rune) bool {
	return IndexRune(s, r) >= 0
}

三个函数很像,包括内部实现。

//子串sep在字符串s中第一次出现的位置,不存在则返回-1。
func Index(s, sep string) int     
//{} 字符串chars中的任一utf-8码值在s中第一次出现的位置,如果不存在或者chars为空字符串则返回-1。
func IndexAny(s, chars string) int {
	if chars == "" {
		// Avoid scanning all of s.
		return -1
	}
	if len(s) > 8 {
		if as, isASCII := makeASCIISet(chars); isASCII {
			for i := 0; i < len(s); i++ {
				if as.contains(s[i]) {
					return i
				}
			}
			return -1
		}
	}
	for i, c := range s {
		for _, m := range chars {
			if c == m {
				return i
			}
		}
	}
	return -1
}

// unicode码值r在s中第一次出现的位置,不存在则返回-1。
func IndexRune(s string, r rune) int {
	switch {
	case 0 <= r && r < utf8.RuneSelf:
		return IndexByte(s, byte(r))
	case r == utf8.RuneError:
		for i, r := range s {
			if r == utf8.RuneError {
				return i
			}
		}
		return -1
	case !utf8.ValidRune(r):
		return -1
	default:
		return Index(s, string(r))
	}
}

其中包含了一层又一层的嵌套,不过逻辑很简单。下面是最后出现的函数,不放源码了

func LastIndex(s, sep string) int
//{} 子串sep在字符串s中最后一次出现的位置,不存在则返回-1。
func LastIndexAny(s, chars string) int
//{} 字符串chars中的任一utf-8码值在s中最后一次出现的位置,如不存在或者chars为空字符串则返回-1。
func LastIndexFunc(s string, f func(rune) bool) int
//{} s中最后一个满足函数f的unicode码值的位置i,不存在则返回-1。

二、EqualFold

判断两个utf-8编码字符串(将unicode大写、小写、标题三种格式字符视为相同)是否相同。 

func EqualFold(s, t string) bool {
	for s != "" && t != "" {
		// 提取第一个字符
		var sr, tr rune
		if s[0] < utf8.RuneSelf {
			sr, s = rune(s[0]), s[1:]
		} else {
			r, size := utf8.DecodeRuneInString(s)
			sr, s = r, s[size:]
		}
		if t[0] < utf8.RuneSelf {
			tr, t = rune(t[0]), t[1:]
		} else {
			r, size := utf8.DecodeRuneInString(t)
			tr, t = r, t[size:]
		}

		// 匹配成功继续,否则返回false
		if tr == sr {
			continue
		}

		if tr < sr {
			tr, sr = sr, tr
		}

		if tr < utf8.RuneSelf && 'A' <= sr && sr <= 'Z' {
			if tr == sr+'a'-'A' {
				continue
			}
			return false
		}

		r := unicode.SimpleFold(sr)
		for r != sr && r < tr {
			r = unicode.SimpleFold(r)
		}
		if r == tr {
			continue
		}
		return false
	}

	return s == t
}

返回s中每个单词的首字母都改为标题格式的字符串拷贝。

func Title(s string) string {
	prev := ' '
	return Map(
		func(r rune) rune {
			if isSeparator(prev) {
				prev = r
				return unicode.ToTitle(r)
			}
			prev = r
			return r
		},
		s)
}

其中,func Map(mapping func(rune) rune, s string) string  // 将s的每一个unicode码值r都替换为mapping(r),返回这些新码值组成的字符串拷贝。如果mapping返回一个负值,将会丢弃该码值而不会被替换。(返回值中对应位置将没有码值)

三、HasPrefix、HasSuffix、Count

判断字符串是否有某个前缀、后缀。实现很简单。

// 判断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
}
// 返回字符串s中有几个不重复的sep子串。  
func Count(s, sep string) int                                {}

// countGeneric实现Count
func countGeneric(s, substr string) int {
	// special case
	if len(substr) == 0 {
		return utf8.RuneCountInString(s) + 1
	}
	n := 0
	for {
		i := Index(s, substr)
		if i == -1 {
			return n
		}
		n++
		s = s[i+len(substr):]
	}
}

 

四、ToLower、ToLowerSpecial、ToTitle、ToTitleSpecial、ToUpper、ToUpperSpecial

字符串转换,这里只放ToUpper的函数,ToLower类似,ToTitle类似

func ToLower(s string) string                                    // 转换为小写    {}
func ToLowerSpecial(_case unicode.SpecialCase, s string) string  // 按_case转换小写  {}
func ToTitle(s string) stringfunc ToLower(s string) string       // 转换为title形式  {}
func ToTitleSpecial(_case unicode.SpecialCase, s string) string  // 按_case转换    {}
func ToUpperSpecial(_case unicode.SpecialCase, s string) string  // 按_case转换为大写 {}
func ToUpper(s string) string {                                  // 转换为大写 
	isASCII, hasLower := true, false
	for i := 0; i < len(s); i++ {
		c := s[i]
		if c >= utf8.RuneSelf {
			isASCII = false
			break
		}
		hasLower = hasLower || (c >= 'a' && c <= 'z')
	}

	if isASCII { // optimize for ASCII-only strings.
		if !hasLower {
			return s
		}
		b := make([]byte, len(s))
		for i := 0; i < len(s); i++ {
			c := s[i]
			if c >= 'a' && c <= 'z' {
				c -= 'a' - 'A'
			}
			b[i] = c
		}
		return string(b)
	}
	return Map(unicode.ToUpper, s)
}

五、Repeat、Replace

Repeat 和 Replace,Repeat还没有用过,看实现挺有意思。

// 返回count个s串联的字符串。  这个实现挺有意思
func Repeat(s string, count int) string {
	if count < 0 {
		panic("strings: negative Repeat count")
	} else if count > 0 && len(s)*count/count != len(s) {
		panic("strings: Repeat count causes overflow")
	}

	b := make([]byte, len(s)*count)
	bp := copy(b, s)
	for bp < len(b) {
		copy(b[bp:], b[:bp])
		bp *= 2
	}
	return string(b)
}
// 返回将s中前n个不重叠old子串都替换为new的新字符串,如果n<0会替换所有old子串。
func Replace(s, old, new string, n int) string {
	if old == new || n == 0 {
		return s // avoid allocation
	}

	if m := Count(s, old); m == 0 {
		return s // avoid allocation
	} else if n < 0 || m < n {
		n = m
	}

	t := make([]byte, len(s)+n*(len(new)-len(old)))
	w := 0
	start := 0
	for i := 0; i < n; i++ {
		j := start
		if len(old) == 0 {
			if i > 0 {
				_, wid := utf8.DecodeRuneInString(s[start:])
				j += wid
			}
		} else {
			j += Index(s[start:], old)
		}
		w += copy(t[w:], s[start:j])
		w += copy(t[w:], new)
		start = j + len(old)
	}
	w += copy(t[w:], s[start:])
	return string(t[0:w])
}

六、Split、SplitN、SplitAfter、SplitAfterN

切割函数的用处也很多,标准库中有四个。 还有两个特殊的分割函数,这里不展开,会用就好。

// 用去掉s中出现的sep的方式进行分割,会分割到结尾,并返回生成的所有片段组成的切片(每一个sep都会进行一次切割,即使两个sep相邻,也会进行两次切割)。如果sep为空字符,Split会将s切分成每一个unicode码值一个字符串。
func Split(s, sep string) []string { return genSplit(s, sep, 0, -1) }
// 同上,参数n决定返回的切片的数目:小于0返回所有 等于0为nil
func SplitN(s, sep string, n int) []string { return genSplit(s, sep, 0, n) }
// 用从s中出现的sep后面切断的方式进行分割
func SplitAfter(s, sep string) []string {return genSplit(s, sep, len(sep), -1)}
// 同SplitN
func SplitAfterN(s, sep string, n int) []string {return genSplit(s, sep, len(sep), n)}

// 返回将字符串按照空白(unicode.IsSpace确定,可以是一到多个连续的空白字符)分割的多个字符串。如果字符串全部是空白或者是空字符串的话,会返回空切片。
func Fields(s string) []string {}
// 类似Fields,但使用函数f来确定分割符(满足f的unicode码值)。如果字符串全部是分隔符或者是空字符串的话,会返回空切片。
func FieldsFunc(s string, f func(rune) bool) []string {}

可以看到这前四个外部切割函数都是通过内部函数genSplit实现的。

func genSplit(s, sep string, sepSave, n int) []string {
	if n == 0 {
		return nil
	}
	if sep == "" {
		return explode(s, n)
	}
	if n < 0 {
		n = Count(s, sep) + 1
	}

	a := make([]string, n)
	n--
	i := 0
	for i < n {
		m := Index(s, sep)
		if m < 0 {
			break
		}
		a[i] = s[:m+sepSave]
		s = s[m+len(sep):]
		i++
	}
	a[i] = s
	return a[:i+1]
}

内部还包含了explode函数,用于将s拆分为一个UTF-8字符串切片。

 

 

未完待续

 


记录每天解决的小问题,积累起来去解决大问题。  

你可能感兴趣的:(Golang基础学习)