【轉】Go語言---strings包(字符串操做)

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 &lt;b&gt;HTML&lt;/b&gt;!
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
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

相關文章
相關標籤/搜索