軌道
/
Go
Go
/
課程大綱
/
正規表示式
正規

正規表示式 在 Go

1 個練習

關於 正規表示式

regexp套件為 Go 提供了正規表達式的支援。

語法

可接受的正規表達式語法,與 Perl、Python 及其他語言所用的一般語法相同。

搜尋樣式和輸入文字都會以 UTF-8 解讀。

使用反引號(`)建立字串時,反斜線(\)不具任何特殊意義,也不會標出定位字元\t或換行字元\n這類特殊字元的開頭:

"\t\n" // regular string literal with 2 characters: a tab and a newline
`\t\n`// raw string literal with 4 characters: two backslashes, a 't', and an 'n'

因此,用反引號來建立正規表達式比較理想,因為這樣就不需要跳脫反斜線:

"\\" // string with a single backslash
`\\` // string with 2 backslashes

編譯樣式:RegExp 型別

要使用正規表達式,我們必須先編譯字串樣式。 這裡的編譯指的是把正規表達式的字串樣式轉換成更容易操作的內部表示法。 每個樣式只需要編譯一次,之後就能重複使用編譯後的正規表達式。 regexp.Regexp型別代表編譯過的正規表達式。 我們可以用regexp.Compile函式把字串樣式編譯成regexp.Regexp。 如果編譯失敗,這個函式會回傳nil和一個錯誤:

re, err := regexp.Compile(`(a|b)+`)
fmt.Println(re, err) // => (a|b)+ <nil>
re, err = regexp.Compile(`a|b)+`)
fmt.Println(re, err) // => <nil> error parsing regexp: unexpected ): `a|b)+`

MustCompile函式是Compile的便利替代方案:

re = regexp.MustCompile(`[a-z]+\d*`)

使用這個函式就不需要處理錯誤。

Caution

只有在確定樣式真的能編譯時,才應該使用MustCompile,否則程式會 panic。

正規表達式的方法

Regexp有 16 個方法可以比對正規表達式並找出符合的文字。 它們的名稱都符合這個正規表達式:

Find(All)?(String)?(Submatch)?(Index)?
  • 如果有All,這個方法會比對整個運算式中連續且不重疊的符合項。
  • 如果有String,引數是字串;否則引數是位元組切片;回傳值會視情況調整。
  • 如果有Submatch,回傳值是用來指出運算式中連續子符合項的切片。
  • 如果有Index,符合項與子符合項會以輸入字串中的位元組索引配對來指出。

另外還有一些方法可以:

  • 用取代字串取代正規表達式的符合項,以及
  • 分割以正規表達式分隔的字串。

整體來說,regexp套件定義了超過 40 個函式和方法。 下面我們會示範幾個方法的用法。 關於這些函式以及其他函式的詳細資訊,請參閱 API 文件。

MatchString範例

MatchString方法會回報字串是否包含正規表達式的任何符合項。

re = regexp.MustCompile(`[a-z]+\d*`)
b = re.MatchString("[a12]")       // => true
b = re.MatchString("12abc34(ef)") // => true
b = re.MatchString(" abc!")       // => true
b = re.MatchString("123 456")     // => false

FindString範例

FindString方法會回傳一個字串,內容是正規表達式最左邊符合項的文字。

re = regexp.MustCompile(`[a-z]+\d*`)
s = re.FindString("[a12]")       // => "a12"
s = re.FindString("12abc34(ef)") // => "abc34"
s = re.FindString(" abc!")       // => "abc"
s = re.FindString("123 456")     // => ""

FindStringSubmatch範例

FindStringSubmatch方法會回傳一個字串切片,內容包含正規表達式最左邊符合項的文字,以及其子運算式符合的部分(如果有的話)。 這可以用來找出符合擷取群組的字串。 回傳值為nil表示沒有符合項。

re = regexp.MustCompile(`[a-z]+(\d*)`)
sl = re.FindStringSubmatch("[a12]")       // => []string{"a12","12"}
sl = re.FindStringSubmatch("12abc34(ef)") // => []string{"abc34","34"}
sl = re.FindStringSubmatch(" abc!")       // => []string{"abc",""}
sl = re.FindStringSubmatch("123 456")     // => <nil>

ReplaceAllString範例

re.ReplaceAllString(src,repl)方法會回傳src的副本,並以取代字串repl取代正規表達式re的符合項。

re = regexp.MustCompile(`[a-z]+\d*`)
s = re.ReplaceAllString("[a12]", "X")       // => "[X]"
s = re.ReplaceAllString("12abc34(ef)", "X") // => "12X(X)"
s = re.ReplaceAllString(" abc!", "X")       // => " X!"
s = re.ReplaceAllString("123 456", "X")     // => "123 456"

Split範例

re.Split(s,n)方法會把文字s分割成以該運算式分隔的子字串,並回傳這些運算式符合項之間子字串的切片。 數量n決定最多要回傳幾個子字串。 如果n<0,這個方法會回傳所有子字串。

re = regexp.MustCompile(`[a-z]+\d*`)
sl = re.Split("[a12]", -1)      // => []string{"[","]"}
sl = re.Split("12abc34(ef)", 2) // => []string{"12","(ef)"}
sl = re.Split(" abc!", -1)      // => []string{" ","!"}
sl = re.Split("123 456", -1)    // => []string{"123 456"}

效能

這個套件提供的 regexp 實作保證執行時間與輸入大小成線性。

注意事項

regexp套件實作了 RE2 正規表達式(\C除外)。 其語法大致上與 PCRE(「Perl Compatible Regular Expression」)相容,但還是有一些差異。 詳細資訊請參閱這篇文章中的「Caveat section」一節。

透過 GitHub 編輯 連結會在新視窗或分頁中開啟

學習 正規表示式

練習已鎖定

再解鎖 2 個練習,就能練習 正規表示式