strings標準庫包主要涉及字符串的基本操做。html
常見字符串的操做有:golang
字符串求長度
求子串
是否存在某個字符或者子串
子串出現的次數(字符串匹配)
字符串分割(切分)成[]string
字符串是否存在某個前綴或後綴
字符或者子串在字符串中首次出現的位置或最後一次出現的位置
經過某個字符串將[]string進行拼接
字符串重複次數
字符串中子串替換
大小寫轉換
......................等等一些基本操做。
因爲string類型能夠當作是一種特殊的slice類型,所以獲取長度能夠用內置的函數len;同時支持 切片 操做,所以,子串獲取很容易。編程
說明:這裏說的字符是rune類型,即一個UTF-8字符(Unicode代碼點)。數組
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------app
子串
是否存在某個字符或子串
// 子串substr在s中,返回true
func Contains(s, substr string) bool
// chars中任何一個Unicode代碼點在s中,返回true
func ContainsAny(s, chars string) bool
// Unicode代碼點r在s中,返回true
func ContainsRune(s string, r rune) bool
示例代碼:ContainsAny 函數說明函數
fmt.Println(strings.ContainsAny("team", "i")) //false
fmt.Println(strings.ContainsAny("failure", "u & i")) //true
fmt.Println(strings.ContainsAny("in failure", "s g")) //true
fmt.Println(strings.ContainsAny("foo", "")) //false
fmt.Println(strings.ContainsAny("", "")) //false
第二個參數 chars 中任意一個字符(Unicode Code Point)若是在第一個參數 s 中存在,則返回true。學習
上述三個函數的源碼都是調用函數Index(子串出現的位置函數),而後和0比較返回true或false。如,contains函數:編碼
func Contains(s, substr string) bool {
return Index(s, substr) >= 0
}
字符或子串在字符串中出現的位置
//返回子串sep在字符串s中第一次出現的索引值,不在的話返回-1.
func Index(s, sep string) int
//chars中任何一個Unicode代碼點在s中首次出現的位置,不存在返回-1
func IndexAny(s, chars string) int
//查找字符 c 在 s 中第一次出現的位置,其中 c 知足 f(c) 返回 true
func IndexFunc(s string, f func(rune) bool) int //rune類型是int32別名,UTF-8字符格式編碼。
//返回字符c在s中第一次出現的位置
func IndexByte(s string, c byte) int //byte是字節類型
// Unicode 代碼點 r 在 s 中第一次出現的位置
func IndexRune(s string, r rune) int
//查找最後一次出現的位置
func LastIndex(s, sep string) int
func LastIndexByte(s string, c byte) int
func LastIndexAny(s, chars string) int
func LastIndexFunc(s string, f func(rune) bool) int
示例:IndexFunc 的例子。spa
fmt.Printf("%d\n", strings.IndexFunc("studygolang", func(c rune) bool {
if c > 'u' {
return true
}
return false
})) //輸出:4 匿名函數傳遞 由於 y 的 Unicode 代碼點大於 u 的代碼點。帶入匿名函數進行比較
子串出現次數
func Count(s, sep string) int //子串在s字符串中出現的次數
(1)、特別說明一下的是當 sep 爲空時,Count 的返回值是:utf8.RuneCountInString(s) + 1.net
(2)、Count 是計算子串在字符串中出現的無重疊的次數
字符串是否有某個前綴或後綴
// s 中是否以 prefix 開始
func HasPrefix(s, prefix string) bool {
return len(s) >= len(prefix) && <strong><span style="color:#ff0000;">s[0:len(prefix)]</span></strong> == prefix
}
// s 中是否以 suffix 結尾
func HasSuffix(s, suffix string) bool {
return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix
}
golang語言中的rune類型
轉載連接:http://ju.outofmemory.cn/entry/245284
Rune 是int32 的別名。用UTF-8 進行編碼。這個類型在何時使用呢?例如須要遍歷字符串中的字符。能夠循環每一個字節(僅在使用US ASCII 編碼字符串時與字符等價,而它們在Go中不存在!)。所以爲了得到實際的字符,須要使用rune類型。在UTF-8 世界的字符有時被稱做runes。一般,當人們討論字符時,多數是指8 位字符。UTF-8 字符可能會有32 位,稱做rune。
例如 s:="Go編程" fmt.Println(len(s)) 輸出結果應該是8 由於中文字符是用3個字節存的。
len(string(rune('編'))) 的結果是3
若是想要得到咱們想要的狀況的話,須要先轉換爲rune切片再使用內置的len函數
fmt.Println(len([]rune(s))) 結果就是 4 了。
因此用string存儲 unicode 的話,若是有中文,按下標是訪問不到的,由於你只能獲得一個 byte 。 要想訪問中文的話,仍是要用rune切片,這樣就能按下表訪問。
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
字符串轉換
func ToUpper(s string) string
func ToLower(s string) string
func ToTitle(s string) string
func ToUpperSpecial(_case unicode.SpecialCase, s string) string
func ToLowerSpecial(_case unicode.SpecialCase, s string) string
func ToTitleSpecial(_case unicode.SpecialCase, s string) string
func Title(s string) string
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
比較
func Compare(a, b string) int //返回不相等-1或者 相等0
func EqualFold(s, t string) bool
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
清理
func Trim(s string, cutset string) string //去除字符串的頭尾子字符串
func TrimLeft(s string, cutset string) string
func TrimRight(s string, cutset string) string
func TrimFunc(s string, f func(rune) bool) string //函數
func TrimLeftFunc(s string, f func(rune) bool) string
func TrimRightFunc(s string, f func(rune) bool) string
func TrimSpace(s string) string //字符串先後空格 fmt.Println(strings.TrimSpace(" \t\n a lone gopher \n\t\r\n")) 輸出:a lone gopher
func TrimPrefix(s, prefix string) string
func TrimSuffix(s, suffix string) string
代碼示例:
func main(){
var s = "aaasddfgaaaa"
fun := func (c rune) bool {
if c != 'a'{
return false
}
return true
}
fmt.Println(strings.TrimFunc(s, fun)) //輸出 sddfg
}
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
拆合函數
Fields
func Fields(s string) []string
func FieldsFunc(s string, f func(rune) bool) []string
Fields 用一個或多個連續的空格分隔字符串 s,返回子字符串的數組(slice)。若是字符串 s 只包含空格,則返回空列表([]string的長度爲0)。其中,空格的定義是 unicode.IsSpace,以前已經介紹過。
因爲是用空格分隔,所以結果中不會含有空格或空子字符串。
FieldsFunc 用這樣的Unicode代碼點 c 進行分隔:知足 f(c) 返回 true。該函數返回[]string。若是字符串 s 中全部的代碼點(unicode code points)都知足f(c)或者 s 是空,則 FieldsFunc 返回空slice。也就是說,咱們能夠經過實現一個回調函數來指定分隔字符串 s 的字符。
示例:
fmt.Printf("Fields are: %q", strings.Fields(" foo bar baz "))
fmt.Println(strings.FieldsFunc(" foo bar baz ", unicode.IsSpace))
split
這四個函數放在一塊兒講,是由於是經過同一個內部函數實現的。
func Split(s, sep string) []string { return genSplit(s, sep, 0, -1) }
func SplitAfter(s, sep string) []string { return genSplit(s, sep, len(sep), -1) }
func SplitN(s, sep string, n int) []string { return genSplit(s, sep, 0, n) }
func SplitAfterN(s, sep string, n int) []string { return genSplit(s, sep, len(sep), n) }
它們都調用了 genSplit 函數。
這四個函數都是經過 sep 進行分割,返回[]string。若是 sep 爲空,至關於分紅一個個的 UTF-8 字符,如 Split("abc",""),獲得的是[a b c]。
Split(s, sep) 和 SplitN(s, sep, -1) 等價;SplitAfter(s, sep) 和 SplitAfterN(s, sep, -1) 等價。
那麼,Split 和 SplitAfter 有啥區別呢?經過這兩句代碼的結果就知道它們的區別了:
fmt.Printf("%q\n", strings.Split("foo,bar,baz", ",")) // ["foo" "bar" "baz"]
fmt.Printf("%q\n", strings.SplitAfter("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)) // ["foo" "bar,baz"]
Join
func Join(a []string, sep string) string
將字符串數組(或slice)鏈接起來能夠經過 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 := <strong><span style="color:#ff0000;">copy</span></strong>(b, a[0])
for _, s := range a[1:] {
bp += copy(b[bp:], sep)
bp += copy(b[bp:], s)
}
return str
標準庫的實現沒有用 bytes 包,固然也不會簡單的經過 + 號鏈接字符串。Go 中是不容許循環依賴的,標準庫中不少時候會出現代碼拷貝,而不是引入某個包。這裏 Join 的實現方式挺好,我我的猜想,不直接使用 bytes 包,也是不想依賴 bytes 包(其實 bytes 中的實現也是 copy 方式)。
字符串重複次數
func Repeat(s string, count int) string
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
替換
// 用 new 替換 s 中的 old,一共替換 n 個。
// 若是 n < 0,則不限制替換次數,即所有替換
func Replace(s, old, new string, n int) string
func Map(mapping func(rune) rune, s string) string //知足函數實現的進行替換
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Replacer
這是一個結構,沒有導出任何字段(字段值小寫),實例化經過
// A Replacer replaces a list of strings with replacements.
type Replacer struct {
r replacer //接口類型
}
// replacer is the interface that a replacement algorithm needs to implement.
type replacer interface {
Replace(s string) string
WriteString(w io.Writer, s string) (n int, err error)
}
func NewReplacer(oldnew ...string) *Replacer
函數進行,其中不定參數 oldnew 是 old-new 對,即進行多個替換。
type Replacer struct { ... }
// 建立一個替換規則,參數爲「查找內容」和「替換內容」的交替形式。
// 替換操做會依次將第 1 個字符串替換爲第 2 個字符串,將第 3 個字符串
// 替換爲第 4 個字符串,以此類推。
// 替換規則能夠同時被多個例程使用。
func NewReplacer(oldnew ...string) *Replacer
// 使用替換規則對 s 進行替換並返回結果。
func (r *Replacer) Replace(s string) string
// 使用替換規則對 s 進行替換並將結果寫入 w。
// 返回寫入的字節數和遇到的錯誤。
func (r *Replacer) WriteString(w io.Writer, s string) (n int, err error)
程序示例:
r := strings.NewReplacer("<", "<", ">", ">")
fmt.Println(r.Replace("This is <b>HTML</b>!")) // 輸出結果是 This is <b>HTML</b>!
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
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 包以後,能夠知道 bytes.NewBufferString 有相似的功能,不過,若是隻是爲了讀取,NewReader 會更高效。
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) WriteTo(w io.Writer) (n int64, err error)
func (r *Reader) Seek(offset int64, whence int) (int64, error)
func (r *Reader) ReadByte() (byte, error)
func (r *Reader) UnreadByte() error
func (r *Reader) ReadRune() (ch rune, size int, err error)
func (r *Reader) UnreadRune() error
func (r *Reader) Len() int
func (r *Reader) Size() int64
func (r *Reader) Reset(s string)
其餘方法不介紹了,都是以前接口的實現,有興趣的能夠看看源碼實現比較簡單易懂,大部分都是根據 i、prevRune 兩個屬性來控制。
參考網址:http://www.cnblogs.com/golove/p/3236300.html
https://books.studygolang.com/The-Golang-Standard-Library-by-Example/chapter02/02.1.html
https://blog.csdn.net/li_101357/article/details/80241224