import "strings"
strings包实现了用于操作字符串的简单函数。
// 判断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。
判断两个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返回一个负值,将会丢弃该码值而不会被替换。(返回值中对应位置将没有码值)
判断字符串是否有某个前缀、后缀。实现很简单。
// 判断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):] } }
字符串转换,这里只放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还没有用过,看实现挺有意思。
// 返回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]) }
切割函数的用处也很多,标准库中有四个。 还有两个特殊的分割函数,这里不展开,会用就好。
// 用去掉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字符串切片。
未完待续
记录每天解决的小问题,积累起来去解决大问题。