golang基礎教程——字元串篇

本文始發於個人公眾號:TechFlow,原創不易,求個關注

今天是golang專題的第6篇文章,這篇主要和大家聊聊golang當中的字元串的使用。

字元串定義

golang當中的字元串本質是只讀的字元型數組,和C語言當中的char[]類似,但是golang為它封裝了一個變數類型,叫做string。知道了string這個類型之後,我們就可以很方便地來初始化:

var str string
str1 := "hello world"
var str2 = "hello world too"

這裡應該沒什麼難度,很好理解。由於這個數組是只讀的,所以我們可以通過下標獲取某一位的字元,但是不允許修改

// 允許
fmt.Println(str1[3])

// 錯誤
str1[3] = 'l'

這個也不是golang的獨創,很多語言當中都有這個限制,因為會將字元串作為const類型存儲在專門的區域。所以不允許字元串進行修改,比如Python也是如此。

除了像是數組一樣,支援下標的訪問之外,go中的字元串還支援拼接以及求長度的操作。我們可以用len函數獲取一個字元串的長度,用+來表示字元串的拼接:

len("hello")
// 5

c := "hello" + "world"
// c="helloworld"

這些本來也屬於常規操作,並不值得一提,但是關於len函數,值得仔細說說。這裡有一個坑,關於utf-8編碼。我們來看下面這個例子:

str := "hello 世界"
fmt.Println(len(str))

按照我們的設想,它返回的應該是8,但是實際上我們這麼操作會得到12。原因很簡單,因為在utf-8編碼當中,一個漢字需要3個位元組編碼。那如果我們想要得到字元串本身的長度,而不是字元串佔據的位元組數,應該怎麼辦呢?這個時候,我們需要用到一個新的結構叫做rune,它表示單個Unicode字元。

所以我們可以將string轉化成rune數組,之後再來計算長度,得到的結果就準確了。

str := "hello 世界"
fmt.Println(len([]rune(str)))

這樣我們得到的結果就是8了,和我們預期一致了。如果你在使用golang的時候,需要用到utf-8編碼,一定要小心。

類型轉換

golang當中的字元串不像Java或者其他語言一樣封裝地非常完善,當我們想要將整形或者是浮點型轉成字元串,或者是想要將字元串轉成整形和浮點型的時候並沒有方法可以直接調用,而必須要通過庫函數。golang當中提供了strconv庫,用來實現字元串的一些操作。

字元串轉整數、浮點數

字元串轉整數的方法有兩個,一個是ParseInt還有一個是ParseUint,這兩個方法本質上都是將字元串轉成整數。區別在於前者會保留符號,後者是無符號的,用於無符號整數。

這兩個函數都接受三個參數,第一個參數是要轉類型的字元串,第二個參數int的進位,比如二進位、八進位還是16進位、32進位。第三個參數表示返回bit的大小,有效值為0,8,16,32,64,如果傳入0就返回int或者是uint類型,如果是32,則會返回int32類型。

函數的返回值有兩個,第一個是類型轉換之後的結果,第二個是一個error,也就是異常類型,表示在轉換的過程當中是否有出現異常。如果沒有異常,那麼這個值會是一個nil。我們判斷異常是否是nil就知道有無錯誤產生,這也是golang當中判斷操作有沒有異常的常規做法。

所以,程式碼寫出來會是這樣的:

value, err := strconv.ParseInt("33225", 10, 32)
if err != nil {
  fmt.Println("error happens")
}

如果你不想要這麼多功能,就想簡單一點將字元串轉成int來使用,也可以通過Atoi函數。相比於ParseInt它要簡單一些, 只需要傳入字元串即可,它默認按照10進位進行轉換,並且轉換之後會返回int類型的整數。

value, err := strconv.Atoi("33234")
if err != nil {
  fmt.Println("error happens")
}

字元串轉浮點數只有一個函數,就是ParseFloat,由於浮點數沒有進位一說,所以它只有兩個參數。第一個參數是待轉的字元串,第二個參數是bit的大小。和ParseInt一樣,它會返回兩個結果,一個是轉換之後的結果,一個是error異常。

value, err := strconv.ParseFloat("33.33", 32)
if err != nil {
  fmt.Println("error happens")
}

整數、浮點數轉字元串

將整數和浮點數轉字元串都是用Format方法,根據我們要轉的類型不同,分為FormatInt和FormatFloat。FormatInt可以認為是ParseInt的逆向操作,我們固定傳入一個int64的類型,和整數的進位。golang會根據我們的數字和進位,將它轉成我們需要的字元串。

如果指定的進位超過10進位,那麼會使用a-z字母來表示大於10的數字。

比如我們把180轉成16進位,會得到b4

num := 180
fmt.Println(strconv.FormatInt(int64(num), 16))

如果我們固定要按照10進位的整數進行轉換,golang還為我們提供了簡化的函數Itoa,默認按照10進位轉化,它等價於FormatInt(i, 10),這樣我們只需要傳入一個值即可。

num := 180
fmt.Println(strconv.Itoa(num))

浮點數轉字元串邏輯大同小異,但是傳參稍有變化。因為浮點數可以用多種方式來表示,比如科學記數法或者是十進位指數法等等。golang當中支援了這些格式,所以允許我們通過傳入參數來指定我們希望得到的字元串的格式

FormatFloat接受4個參數,第一個參數就是待轉換的浮點數,第二個參數表示我們希望轉換之後得到的格式。一共有’f’, ‘b’, ‘e’, ‘E’, ‘g’, ‘G’這幾種格式。

看起來有些眼花繚亂,我們仔細說說。

‘f’ 表示普通模式:(-ddd.dddd)

‘b’ 表示指數為二進位:(-ddddp±ddd)

‘e’ 表示十進位指數,也就是科學記數法的模式:(-d.dddde±dd)

‘E’ 和’e’一樣,都是科學記數法的模式,只不過字母e大寫:(-d.ddddE±dd)

‘g’ 表示指數很大時用’e’模式,否則用『f’模式

‘G’ 表示指數很大時用』E’模式,否則用’f’模式

我們來看個例子:

num := 23423134.323422
fmt.Println(strconv.FormatFloat(float64(num), 'f', -1, 64))
fmt.Println(strconv.FormatFloat(float64(num), 'b', -1, 64))
fmt.Println(strconv.FormatFloat(float64(num), 'e', -1, 64))
fmt.Println(strconv.FormatFloat(float64(num), 'E', -1, 64))
fmt.Println(strconv.FormatFloat(float64(num), 'g', -1, 64))
fmt.Println(strconv.FormatFloat(float64(num), 'G', -1, 64))

得到的結果如下:

字元串和bool型轉換

除了常用的整數和浮點數之外,strconv還支援與bool類型進行轉換

其中將字元串轉成bool類型用的是ParseBool,它只有一個參數,只接受0, 1, t, f, T, F, ture, false, True, False, TRUE, FALSE這幾種取值,否則會返回錯誤。

flag, err := strconv.ParseBool('t')
if err != nil {
  fmt.Println("error happens")
}

將bool轉字元串調用FormatBool方法,它也只有一個參數,就是一個bool類型的變數,返回值也是確定的,如果是True就返回”true”, 如果是False就返回”false”。

fmt.Println(strconv.FormatBool(true))

字元串運算包

前面介紹的strconv包是golang當中字元串的一個轉換操作包,可以用來將字元串轉成其他類型,將其他類型轉化成字元串。關於字元串本身的一些操作,還有一個專門的包叫做strings

字元串比較

我們可以通過strings.Compare來比較兩個字元串的大小,這個函數類似於C語言當中的strcmp,會返回一個int。

cmp := strings.Compare(str1, str2)

cmp等於-1表示str1字典序小於str2,如果str1和str2相等,cmp等於0。如果cmp=1,表示str1字典序大於str2.

查找函數

我們可以用Index函數查找一個字元串中子串的位置,它會返回第一次出現的位置,如果不存在返回-1.

var theInd = strings.Index(str, "sub")

類似的方法是LastIndex,它返回的是出現的最後一個位置,同樣,如果不存在返回-1.

var theLastIdx = strings.LastIndex(str, "last")

Count和Repeat

我們可以用Count來統計子串在整體當中出現的次數。

strings.Count("abcabcabababc", "abc") 

第一個參數是母串,第二個參數是子串。如果子串為空,則返回母串的長度+1.

有count自然就有重複,我們可以用Repeat方法來講字元串重複指定的次數:

repeat := strings.Repeat("abc", 10)

Replace、Split和Join

還有Replace函數,可以替換字元串中的部分。這個函數接收四個參數,分別是字元串,匹配串和目標串,還有替換的次數。如果小於0,表示全部替換。

str := "aaaddc"

strings.Replace(str, "a", "b", 1) // baaddc
strings.Replace(str, "a", "b", -1)

我們還可以通過Split方法來分割字元串,它的使用方法和Python當中的split一樣,我們傳入字元串與分隔符,會返回根據分隔符分割之後的字元串數組:

str := "abc,bbc,bbd"

slice := strings.Split(str, ",")

除了Split之外,我們也經常使用它的逆操作也就是Join。通過我們指定的分隔符,將一個字元串數組拼接在一起。

slice := []string{"aab", "aba", "baa"}
str := strings.Join(slice, ",")

strings當中的函數除了剛才列舉的之外還有很多,比如用來去除字元串首尾多餘字元的Trim和TrimLeft,判斷是否包含前綴的HasPrefix和判斷是否包含後綴的HasSufix等等,由於篇幅限制,不一一列舉了,大家用到的時候可以查閱strings的api文檔。

總結

到這裡,關於golang當中string的一些基本用法就介紹完了。一般來說,我們日常需要用到的功能,strings和strconv這兩個庫就足夠使用了。初學者可能經常會把這兩個庫搞混淆,其實很容易分清,strings當中封裝的是操作字元串的一些函數。比如字元串判斷、join、split等各種處理,而strconv是專門用來字元串和其他類型進行轉換的,除此之外基本上沒有其他的功能。牢記這兩點之後,很容易區分開。

今天介紹的api有些多,如果記不過來也沒有關係, 我們只需要大概有一個印象即可,具體可以使用到的時候再去查閱相關的資料。

如果覺得有所收穫,請給我一個關注