go標準庫的學習-regexp

參考:https://studygolang.com/pkgdochtml

導入方式:java

import "regexp"

regexp包實現了正則表達式搜索。golang

正則表達式採用RE2語法(除了\c、\C),和Perl、Python等語言的正則基本一致。正則表達式

參見http://code.google.com/p/re2/wiki/Syntax數組

 

1)判斷是否匹配安全

下面的三個函數都實現了同一個功能,就是判斷pattern是否和輸入源匹配,匹配就返回true,若是解析正則出錯則返回error。三者的區別在於輸入源不一樣多線程

func Match

func Match(pattern string, b []byte) (matched bool, err error)

Match檢查b中是否存在匹配pattern的子序列。更復雜的用法請使用Compile函數和Regexp對象。函數

func MatchString

func MatchString(pattern string, s string) (matched bool, err error)

MatchString相似Match,但匹配對象是字符串。post

func MatchReader

func MatchReader(pattern string, r io.RuneReader) (matched bool, err error)

MatchReader相似Match,但匹配對象是io.RuneReader。google

舉例:

package main 
import(
    "fmt"
    "regexp"
)

func main() {
    matched, err := regexp.MatchString("foo.*", "seafood")
    fmt.Println(matched, err)
    matched, err = regexp.MatchString("bar.*", "seafood")
    fmt.Println(matched, err)
    matched, err = regexp.MatchString("a(b", "seafood")
    fmt.Println(matched, err)
}

返回:

userdeMBP:go-learning user$ go run test.go
true
false
userdeMBP:go-learning user$ go run test.go
true <nil>
false <nil>
false error parsing regexp: missing closing ): `a(b`

 

 固然你也可使用下面的函數,結果是等價的:

type Regexp

type Regexp struct {
    // 內含隱藏或非導出字段
}

Regexp表明一個編譯好的正則表達式。Regexp能夠被多線程安全地同時使用。

func (*Regexp) Match

func (re *Regexp) Match(b []byte) bool

Match檢查b中是否存在匹配pattern的子序列。

func (*Regexp) MatchString

func (re *Regexp) MatchString(s string) bool

MatchString相似Match,但匹配對象是字符串。

舉例:

package main 
import(
    "fmt" "regexp" ) func main() { var validID = regexp.MustCompile(`^[a-z]+\[[0-9]+\]$`) fmt.Println(validID.MatchString("adam[23]")) //true fmt.Println(validID.MatchString("Job[48]")) //false fmt.Println(validID.MatchString("snakey")) //false } 

func (*Regexp) MatchReader

func (re *Regexp) MatchReader(r io.RuneReader) bool

MatchReader相似Match,但匹配對象是io.RuneReader。

 

2)經過正則獲取內容

 Match模式只能用來對字符串的判斷,若是想要截取部分字符串、過濾字符串或者提取出符合條件的一批字符串,就應該使用更復雜的方法

1》解析正則表達式的方法有:

func Compile

func Compile(expr string) (*Regexp, error)

Compile解析並返回一個正則表達式。若是成功返回,該Regexp就可用於匹配文本。

在匹配文本時,該正則表達式會盡量早的開始匹配,而且在匹配過程當中選擇回溯搜索到的第一個匹配結果。這種模式被稱爲「leftmost-first」,Perl、Python和其餘實現都採用了這種模式,但本包的實現沒有回溯的損耗。對POSIX的「leftmost-longest」模式,參見CompilePOSIX。

func CompilePOSIX

func CompilePOSIX(expr string) (*Regexp, error)

相似Compile但會將語法約束到POSIX ERE(egrep)語法,並將匹配模式設置爲leftmost-longest。

在匹配文本時,該正則表達式會盡量早的開始匹配,而且在匹配過程當中選擇搜索到的最長的匹配結果。這種模式被稱爲「leftmost-longest」,POSIX採用了這種模式(早期正則的DFA自動機模式)。

然而,可能會有多個「leftmost-longest」匹配,每一個都有不一樣的組匹配狀態,本包在這裏和POSIX不一樣。在全部可能的「leftmost-longest」匹配裏,本包選擇回溯搜索時第一個找到的,而POSIX會選擇候選結果中第一個組匹配最長的(可能有多個),而後再從中選出第二個組匹配最長的,依次類推。POSIX規則計算困難,甚至沒有良好定義。

參見http://swtch.com/~rsc/regexp/regexp2.html#posix獲取細節。

func MustCompile

func MustCompile(str string) *Regexp

MustCompile相似Compile但會在解析失敗時panic,主要用於全局正則表達式變量的安全初始化。

func MustCompilePOSIX

func MustCompilePOSIX(str string) *Regexp

MustCompilePOSIX相似CompilePOSIX但會在解析失敗時panic,主要用於全局正則表達式變量的安全初始化。

 

上面的函數用於解析正則表達式是否合法,若是正確,則會返回一個Regexp,而後就可以利用該對象在任意字符串上執行須要的操做

帶POSIX後綴的不一樣點在於其使用POSIX語法,該語法使用最長最左方式搜索,而不帶該後綴的方法是採用最左方式搜索(如[a-z]{2,4}這樣的正則表達式,應用於"aa09aaa88aaaa"這個文本串時,帶POSIX後綴的將返回aaaa,不帶後綴的則返回aa)。

前綴有Must的函數表示在解析正則表達式時,若是匹配模式串不知足正確的語法則直接panic,而不加Must前綴的將只是返回錯誤

2》解析完正則表達式後可以進行的操做有

1〉查找操做——即前綴帶有Find的函數

func (*Regexp) Find

func (re *Regexp) Find(b []byte) []byte

Find返回保管正則表達式re在b中的最左側的一個匹配結果的[]byte切片。若是沒有匹配到,會返回nil。

func (*Regexp) FindString

func (re *Regexp) FindString(s string) string

Find返回保管正則表達式re在b中的最左側的一個匹配結果的字符串。若是沒有匹配到,會返回"";但若是正則表達式成功匹配了一個空字符串,也會返回""。若是須要區分這種狀況,請使用FindStringIndex 或FindStringSubmatch

舉例:

package main 
import(
    "fmt"
    "regexp"
)

func main() {
  re := regexp.MustCompile("fo.?")
  fmt.Printf("%q\n", re.FindString("seafood")) //"foo"
  fmt.Printf("%q\n", re.Find([]byte("seafood"))) //"foo"
}

 

下面兩個函數跟上面的兩個函數的差異在與可以使用第二個參數來決定返回幾個匹配結果:

func (*Regexp) FindAll

func (re *Regexp) FindAll(b []byte, n int) [][]byte

Find返回保管正則表達式re在b中的全部不重疊的匹配結果的[][]byte切片。若是沒有匹配到,會返回nil。

func (*Regexp) FindAllString

func (re *Regexp) FindAllString(s string, n int) []string

Find返回保管正則表達式re在b中的全部不重疊的匹配結果的[]string切片。若是沒有匹配到,會返回nil。

 舉例:
package main 
import(
    "fmt" "regexp" ) func main() { re := regexp.MustCompile("a.") fmt.Println(re.FindAllString("paranormal", -1)) //-1表示返回全部匹配的值,[ar an al] fmt.Println(re.FindAllString("paranormal", 2)) //2表示返回2個匹配的值,[ar an] fmt.Println(re.FindAllString("paranormal", 1)) //1表示返回1個匹配的值,[ar] fmt.Println(re.FindAllString("paranormal", 0)) //0表示返回0個匹配的值,[] fmt.Println(re.FindAllString("graal", -1)) //[aa] fmt.Println(re.FindAllString("none", -1)) //[] }

 

下面三個函數的做用是查找索引:

func (*Regexp) FindIndex

func (re *Regexp) FindIndex(b []byte) (loc []int)

Find返回保管正則表達式re在b中的最左側的一個匹配結果的起止位置的切片(顯然len(loc)==2)。匹配結果能夠經過起止位置對b作切片操做獲得:b[loc[0]:loc[1]]。若是沒有匹配到,會返回nil。

func (*Regexp) FindStringIndex

func (re *Regexp) FindStringIndex(s string) (loc []int)

Find返回保管正則表達式re在b中的最左側的一個匹配結果的起止位置的切片(顯然len(loc)==2)。匹配結果能夠經過起止位置對b作切片操做獲得:b[loc[0]:loc[1]]。若是沒有匹配到,會返回nil。

func (*Regexp) FindReaderIndex

func (re *Regexp) FindReaderIndex(r io.RuneReader) (loc []int)

Find返回保管正則表達式re在b中的最左側的一個匹配結果的起止位置的切片(顯然len(loc)==2)。匹配結果能夠在輸入流r的字節偏移量loc[0]到loc[1]-1(包括兩者)位置找到。若是沒有匹配到,會返回nil。

舉例:

package main 
import(
    "fmt"
    "regexp"
)

func main() {
    re := regexp.MustCompile("ab?")
    fmt.Println(re.FindStringIndex("tablett")) //[1 3],表示匹配到的字符在"tablett"的[1,3]切片處
    fmt.Println(re.FindStringIndex("foo") == nil) //沒有匹配到會返回nil
    fmt.Println(re.FindIndex([]byte("tablett"))) //[1 3],表示匹配到的字符在"tablett"的[1,3]切片處
    fmt.Println(re.FindIndex([]byte("foo")) == nil) //沒有匹配到會返回nil
}

下面兩個函數和上面的函數的區別在與可以使用第二個參數決定返回匹配的數量:

func (*Regexp) FindAllIndex

func (re *Regexp) FindAllIndex(b []byte, n int) [][]int

Find返回保管正則表達式re在b中的全部不重疊的匹配結果的起止位置的切片。若是沒有匹配到,會返回nil。

func (*Regexp) FindAllStringIndex

func (re *Regexp) FindAllStringIndex(s string, n int) [][]int

Find返回保管正則表達式re在b中的全部不重疊的匹配結果的起止位置的切片。若是沒有匹配到,會返回nil。

舉例:

package main 
import(
    "fmt"
    "regexp"
)

func main() {
    re := regexp.MustCompile("a.")
    fmt.Println(re.FindAllStringIndex("paranormal", -1)) //[[1 3] [3 5] [8 10]],-1表示匹配所有
    fmt.Println(re.FindAllStringIndex("paranormal", 2)) //[[1 3] [3 5]] ,2表示返回匹配的兩個的索引切片
    fmt.Println(re.FindAllStringIndex("paranormal", 1)) //[[1 3]] ,1表示返回匹配的一個的索引切片
    fmt.Println(re.FindAllIndex([]byte("paranormal"), -1)) //[[1 3] [3 5] [8 10]]
    fmt.Println(re.FindAllIndex([]byte("paranormal"), 2)) //[[1 3] [3 5]]
    fmt.Println(re.FindAllIndex([]byte("paranormal"), 1)) //[[1 3]]
}

 

下面兩個函數使用在正則表達式有分組時,切片中的第一個索引值爲整個輸入字符串知足正則表達式的輸出,後面的索引值則爲知足分組的字符串:

func (*Regexp) FindSubmatch

func (re *Regexp) FindSubmatch(b []byte) [][]byte

Find返回一個保管正則表達式re在b中的最左側的一個匹配結果以及(可能有的)分組匹配的結果的[][]byte切片。若是沒有匹配到,會返回nil。

func (*Regexp) FindStringSubmatch

func (re *Regexp) FindStringSubmatch(s string) []string

Find返回一個保管正則表達式re在b中的最左側的一個匹配結果以及(可能有的)分組匹配的結果的[]string切片。若是沒有匹配到,會返回nil。

舉例:

package main 
import(
    "fmt"
    "regexp"
)

func main() {
    re := regexp.MustCompile("a(x*)b(y|z)c")
    fmt.Printf("%q\n", re.FindSubmatch([]byte("-axxxbyc-"))) //["axxxbyc" "xxx" "y"]
    fmt.Printf("%q\n", re.FindSubmatch([]byte("-abzc-"))) //["abzc" "" "z"]
    fmt.Printf("%q\n", re.FindSubmatch([]byte("-aczc-"))) //[],整個都不匹配,更沒有分組匹配,將返回空數組
    fmt.Printf("%q\n", re.FindStringSubmatch("-axxxbyc-")) //["axxxbyc" "xxx" "y"]
    fmt.Printf("%q\n", re.FindStringSubmatch("-abzc-")) //["abzc" "" "z"]
    fmt.Printf("%q\n", re.FindStringSubmatch("-aczc-")) //[],整個都不匹配,更沒有分組匹配,將返回空數組
}

下面兩個函數和上面兩個函數的區別在與可以使用第二個參數決定返回匹配的數量:

func (*Regexp) FindAllSubmatch

func (re *Regexp) FindAllSubmatch(b []byte, n int) [][][]byte

Find返回一個保管正則表達式re在b中的全部不重疊的匹配結果及其對應的(可能有的)分組匹配的結果的[][][]byte切片。若是沒有匹配到,會返回nil。

func (*Regexp) FindAllStringSubmatch

func (re *Regexp) FindAllStringSubmatch(s string, n int) [][]string

Find返回一個保管正則表達式re在b中的全部不重疊的匹配結果及其對應的(可能有的)分組匹配的結果的[][]string切片。若是沒有匹配到,會返回nil。

舉例:

package main 
import(
    "fmt"
    "regexp"
)

func main() {
    re := regexp.MustCompile("a(x*)b(y|z)c")
    fmt.Printf("%q\n", re.FindAllSubmatch([]byte("-axxxbyc-axxbyc-axbyc-"), -1)) //[["axxxbyc" "xxx" "y"] ["axxbyc" "xx" "y"] ["axbyc" "x" "y"]]
    fmt.Printf("%q\n", re.FindAllSubmatch([]byte("-axxxbyc-axxbyc-axbyc-"), 2)) //[["axxxbyc" "xxx" "y"] ["axxbyc" "xx" "y"]]
    fmt.Printf("%q\n", re.FindAllSubmatch([]byte("-axxxbyc-axxbyc-axbyc-"), 1)) //[["axxxbyc" "xxx" "y"]]
    fmt.Printf("%q\n", re.FindAllSubmatch([]byte("-abzc-abzc-"), -1)) //[["abzc" "" "z"] ["abzc" "" "z"]]
    fmt.Printf("%q\n", re.FindAllSubmatch([]byte("-abzc-abzc-"), 1)) //[["abzc" "" "z"]]
    fmt.Printf("%q\n", re.FindAllSubmatch([]byte("-aczc-"), -1)) //[],整個都不匹配,更沒有分組匹配,將返回空數組

    fmt.Printf("%q\n", re.FindAllStringSubmatch("-axxxbyc-axxbyc-axbyc-", -1)) //[["axxxbyc" "xxx" "y"] ["axxbyc" "xx" "y"] ["axbyc" "x" "y"]]
    fmt.Printf("%q\n", re.FindAllStringSubmatch("-axxxbyc-axxbyc-axbyc-", 2)) //[["axxxbyc" "xxx" "y"] ["axxbyc" "xx" "y"]]
    fmt.Printf("%q\n", re.FindAllStringSubmatch("-axxxbyc-axxbyc-axbyc-", 1)) //[["axxxbyc" "xxx" "y"]]
    fmt.Printf("%q\n", re.FindAllStringSubmatch("-abzc-abzc-", -1)) //[["abzc" "" "z"] ["abzc" "" "z"]]
    fmt.Printf("%q\n", re.FindAllStringSubmatch("-abzc-abzc-", 1)) //[["abzc" "" "z"]]
    fmt.Printf("%q\n", re.FindAllStringSubmatch("-aczc-", -1)) //[],整個都不匹配,更沒有分組匹配,將返回空數組
}

 

下面三個函數實現分組匹配查找索引:

func (*Regexp) FindSubmatchIndex

func (re *Regexp) FindSubmatchIndex(b []byte) []int

Find返回一個保管正則表達式re在b中的最左側的一個匹配結果以及(可能有的)分組匹配的結果的起止位置的切片。匹配結果和分組匹配結果能夠經過起止位置對b作切片操做獲得:b[loc[2*n]:loc[2*n+1]]。若是沒有匹配到,會返回nil。

func (*Regexp) FindStringSubmatchIndex

func (re *Regexp) FindStringSubmatchIndex(s string) []int

Find返回一個保管正則表達式re在b中的最左側的一個匹配結果以及(可能有的)分組匹配的結果的起止位置的切片。匹配結果和分組匹配結果能夠經過起止位置對b作切片操做獲得:b[loc[2*n]:loc[2*n+1]]。若是沒有匹配到,會返回nil。

func (*Regexp) FindReaderSubmatchIndex

func (re *Regexp) FindReaderSubmatchIndex(r io.RuneReader) []int

Find返回一個保管正則表達式re在b中的最左側的一個匹配結果以及(可能有的)分組匹配的結果的起止位置的切片。匹配結果和分組匹配結果能夠在輸入流r的字節偏移量loc[0]到loc[1]-1(包括兩者)位置找到。若是沒有匹配到,會返回nil。

舉例:

package main 
import(
    "fmt"
    "regexp"
)

func main() {
    re := regexp.MustCompile("a(x*)b(y|z)c")
    fmt.Println(re.FindSubmatchIndex([]byte("-axxxbyc-"))) //[1 8 2 5 6 7],即總體匹配字符串"-axxxbyc-"的[1,8]切片,分組1匹配[2,5],分組2匹配[6,7]切片
    fmt.Println(re.FindSubmatchIndex([]byte("-abzc-"))) //[1 5 2 2 3 4]
    fmt.Println(re.FindSubmatchIndex([]byte("-aczc-"))) //[],整個都不匹配,更沒有分組匹配,將返回空數組
    fmt.Println(re.FindStringSubmatchIndex("-axxxbyc-")) //[1 8 2 5 6 7]
    fmt.Println(re.FindStringSubmatchIndex("-abzc-")) //[1 5 2 2 3 4]
    fmt.Println(re.FindStringSubmatchIndex("-aczc-")) //[],整個都不匹配,更沒有分組匹配,將返回空數組
}

下面兩個函數和上面三個函數的區別在與可以使用第二個參數決定返回匹配的數量:

func (*Regexp) FindAllSubmatchIndex

func (re *Regexp) FindAllSubmatchIndex(b []byte, n int) [][]int

Find返回一個保管正則表達式re在b中的全部不重疊的匹配結果及其對應的(可能有的)分組匹配的結果的起止位置的切片(第一層表示第幾個匹配結果,完整匹配和分組匹配的起止位置對在第二層)。若是沒有匹配到,會返回nil。

func (*Regexp) FindAllStringSubmatchIndex

func (re *Regexp) FindAllStringSubmatchIndex(s string, n int) [][]int

Find返回一個保管正則表達式re在b中的全部不重疊的匹配結果及其對應的(可能有的)分組匹配的結果的起止位置的切片(第一層表示第幾個匹配結果,完整匹配和分組匹配的起止位置對在第二層)。若是沒有匹配到,會返回nil。

 舉例:
package main 
import(
    "fmt"
    "regexp"
)

func main() {
    re := regexp.MustCompile("a(x*)b(y|z)c")
    fmt.Println(re.FindAllSubmatchIndex([]byte("-axxxbyc-axxbyc-axbyc-"), -1)) //[[1 8 2 5 6 7] [9 15 10 12 13 14] [16 21 17 18 19 20]]
    fmt.Println(re.FindAllSubmatchIndex([]byte("-axxxbyc-axxbyc-axbyc-"), 2)) //[[1 8 2 5 6 7] [9 15 10 12 13 14]]
    fmt.Println(re.FindAllSubmatchIndex([]byte("-axxxbyc-axxbyc-axbyc-"), 1)) //[[1 8 2 5 6 7]]
    fmt.Println(re.FindAllSubmatchIndex([]byte("-abzc-abzc-"), -1)) //[[1 5 2 2 3 4] [6 10 7 7 8 9]]
    fmt.Println(re.FindAllSubmatchIndex([]byte("-abzc-abzc-"), 1)) //[[1 5 2 2 3 4]]
    fmt.Println(re.FindAllSubmatchIndex([]byte("-aczc-"), -1)) //[],整個都不匹配,更沒有分組匹配,將返回空數組

    fmt.Println(re.FindAllStringSubmatchIndex("-axxxbyc-axxbyc-axbyc-", -1)) //[[1 8 2 5 6 7] [9 15 10 12 13 14] [16 21 17 18 19 20]]
    fmt.Println(re.FindAllStringSubmatchIndex("-axxxbyc-axxbyc-axbyc-", 2)) //[[1 8 2 5 6 7] [9 15 10 12 13 14]]
    fmt.Println(re.FindAllStringSubmatchIndex("-axxxbyc-axxbyc-axbyc-", 1)) //[[1 8 2 5 6 7]]
    fmt.Println(re.FindAllStringSubmatchIndex("-abzc-abzc-", -1)) //[[1 5 2 2 3 4] [6 10 7 7 8 9]]
    fmt.Println(re.FindAllStringSubmatchIndex("-abzc-abzc-", 1)) //[[1 5 2 2 3 4]]
    fmt.Println(re.FindAllStringSubmatchIndex("-aczc-", -1)) //[],整個都不匹配,更沒有分組匹配,將返回空數組
}

 

2)替換操做-即前綴帶有Replace的函數

 

 

 

func (*Regexp) ReplaceAllLiteral

func (re *Regexp) ReplaceAllLiteral(src, repl []byte) []byte

ReplaceAllLiteral返回src的一個拷貝,將src中全部re的匹配結果都替換爲repl。repl參數被直接使用,不會使用Expand進行擴展。

func (*Regexp) ReplaceAllLiteralString

func (re *Regexp) ReplaceAllLiteralString(src, repl string) string

ReplaceAllLiteralString返回src的一個拷貝,將src中全部re的匹配結果都替換爲repl。repl參數被直接使用,不會使用Expand進行擴展。

 舉例:
package main 
import(
    "fmt"
    "regexp"
)

func main() {
    re := regexp.MustCompile("a(x*)b") //進行最左最長匹配
    fmt.Println(re.ReplaceAllLiteralString("-ab-axxb-", "T"))
    fmt.Println(re.ReplaceAllLiteralString("-ab-axxb-", "$1"))
    fmt.Println(re.ReplaceAllLiteralString("-ab-axxb-", "${1}"))
}

返回:

userdeMBP:go-learning user$ go run test.go
-T-T-
-$1-$1-
-${1}-${1}-

 下面兩個函數和上面的區別在與當使用$時,不會再將其看成一個簡單的字符,而是進行規則替換。瞭解規則可去看下面的Expand函數

func (*Regexp) ReplaceAll

func (re *Regexp) ReplaceAll(src, repl []byte) []byte

ReplaceAllLiteral返回src的一個拷貝,將src中全部re的匹配結果都替換爲repl。在替換時,repl中的'$'符號會按照Expand方法的規則進行解釋和替換,例如$1會被替換爲第一個分組匹配結果。

func (*Regexp) ReplaceAllString

func (re *Regexp) ReplaceAllString(src, repl string) string

ReplaceAllLiteral返回src的一個拷貝,將src中全部re的匹配結果都替換爲repl。在替換時,repl中的'$'符號會按照Expand方法的規則進行解釋和替換,例如$1會被替換爲第一個分組匹配結果。

 舉例:

package main 
import(
    "fmt"
    "regexp"
)

func main() {
    re := regexp.MustCompile("a(x*)b")
    fmt.Println(re.ReplaceAllString("-ab-axxb-", "T")) //-T-T-

    //這裏$1表示的是每個匹配的第一個分組匹配結果
    //這裏第一個匹配的第一個分組匹配爲空,即將匹配的ab換爲空值;
    //第二個匹配的第一個分組匹配爲xx,即將匹配的axxb換爲xx
    fmt.Println(re.ReplaceAllString("-ab-axxb-", "$1")) //--xx-
    fmt.Println(re.ReplaceAllString("-ab-axxb-", "${1}w"))//-w-xxw-

    //由於這個例子每一個匹配的第二個分組匹配都爲空,因此將全部匹配字符串都替換成了空值
    fmt.Println(re.ReplaceAllString("-ab-axxb-", "${2}"))//---
}

 

 

func (*Regexp) ReplaceAllFunc

func (re *Regexp) ReplaceAllFunc(src []byte, repl func([]byte) []byte) []byte

ReplaceAllLiteral返回src的一個拷貝,將src中全部re的匹配結果(設爲matched)都替換爲repl(matched)。repl返回的切片被直接使用,不會使用Expand進行擴展。

func (*Regexp) ReplaceAllStringFunc

func (re *Regexp) ReplaceAllStringFunc(src string, repl func(string) string) string

ReplaceAllLiteral返回src的一個拷貝,將src中全部re的匹配結果(設爲matched)都替換爲repl(matched)。repl返回的字符串被直接使用,不會使用Expand進行擴展。

 舉例:

服務端爲:

package main 
import(
    "fmt"
    "net/http"
    "log"
    "html/template"
)


func index(w http.ResponseWriter, r *http.Request){
    fmt.Fprintf(w, "hello world") //將html寫到w中,w中的內容將會輸出到客戶端中
}

func login(w http.ResponseWriter, r *http.Request){
    fmt.Println("method", r.Method) //得到請求的方法
    r.ParseForm()
    if r.Method == "GET"{
        html := `<html>
<HEAD>
<title></title>
</HEAD>
<body>


<form action="http://localhost:9090/login" method="post">
    username: <input type="text" name="username">
    password: <input type="text" name="password">
    <input type="submit" value="login">
    {{.}}
</form>


</body>
</html>`
        t := template.Must(template.New("test").Parse(html))
        w.Header().Set("Content-Type", "text/html")
        t.Execute(w, nil)
    }
}

func main() {
    http.HandleFunc("/", index)              //設置訪問的路由
    http.HandleFunc("/login", login)         //設置訪問的路由
    err := http.ListenAndServe(":9090", nil) //設置監聽的端口
    if err != nil{
        log.Fatal("ListenAndServe : ", err)
    }
}

客戶端

package main 
import(
    "fmt"
    "regexp"
    "net/http"
    "strings"
    "io/ioutil"
)

func main() {
    resp, err := http.Get("http://localhost:9090/login")
    if err != nil{
        fmt.Println("http get err")
    }
    defer resp.Body.Close()

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil{
        fmt.Println("http read err")
        return
    }
    src := string(body)
    fmt.Println("--------begin--------")
    fmt.Println(src)

    //將HTML標籤都轉成小寫
    re, _ := regexp.Compile("\\<[\\S\\s]+?\\>")
    src = re.ReplaceAllStringFunc(src, strings.ToLower)
    fmt.Println("--------one--------")
    fmt.Println(src)

    //去除head
    re, _ = regexp.Compile("\\<head[\\S\\s]+?\\</head\\>")
    src = re.ReplaceAllString(src, "")
    fmt.Println("--------two--------")
    fmt.Println(src)

    //去除全部尖括號內的HTML代碼,並換成換行符
    re, _ = regexp.Compile("\\<[\\S\\s]+?\\>")
    src = re.ReplaceAllString(src, "\n")
    fmt.Println("--------three--------")
    fmt.Println(src)   

    //去除連續的換行符
    re, _ = regexp.Compile("\\s{2,}")
    src = re.ReplaceAllString(src, "\n")
    fmt.Println("--------four--------")
    fmt.Println(src)
    //去掉空行
    fmt.Println("--------five--------")
    fmt.Println(strings.TrimSpace(src)) //
}

返回:

userdeMacBook-Pro:go-learning user$ go run test.go
--------begin--------
<html>
<HEAD>
<title></title>
</HEAD>
<body>


<form action="http://localhost:9090/login" method="post">
    username: <input type="text" name="username">
    password: <input type="text" name="password">
    <input type="submit" value="login">
    
</form>


</body>
</html>
--------one--------
<html>
<head>
<title></title>
</head>
<body>


<form action="http://localhost:9090/login" method="post">
    username: <input type="text" name="username">
    password: <input type="text" name="password">
    <input type="submit" value="login">
    
</form>


</body>
</html>
--------two--------
<html>

<body>


<form action="http://localhost:9090/login" method="post">
    username: <input type="text" name="username">
    password: <input type="text" name="password">
    <input type="submit" value="login">
    
</form>


</body>
</html>
--------three--------









    username: 

    password: 

    

    








--------four--------

username:
password:

--------five--------
username:
password:

 

3)前綴爲Expand的函數

func (*Regexp) Expand

func (re *Regexp) Expand(dst []byte, template []byte, src []byte, match []int) []byte

Expand返回新生成的將template添加到dst後面的切片。在添加時,Expand會將template中的變量替換爲從src匹配的結果。match應該是被FindSubmatchIndex返回的匹配結果起止位置索引。(一般就是匹配src,除非你要將匹配獲得的位置用於另外一個[]byte)

在template參數裏,一個變量表示爲格式如:$name或${name}的字符串,其中name是長度>0的字母、數字和下劃線的序列。一個單純的數字字符名如$1會做爲捕獲分組的數字索引;其餘的名字對應(?P<name>...)語法產生的命名捕獲分組的名字,便可以在使用Compile解析正則表達式的時候使用(?P<name>...)語法命名匹配到的內容,而後以後可以使用$name或${name}表示匹配到的值

超出範圍的數字索引、索引對應的分組未匹配到文本、正則表達式中未出現的分組名,都會被替換爲空切片。

$name格式的變量名,name會盡量取最長序列:$1x等價於${1x}而非${1}x,$10等價於${10}而非${1}0。所以$name適用在後跟空格/換行等字符的狀況,${name}適用全部狀況。

若是要在輸出中插入一個字面值'$',在template裏可使用$$。

func (*Regexp) ExpandString

func (re *Regexp) ExpandString(dst []byte, template string, src string, match []int) []byte

ExpandString相似Expand,但template和src參數爲字符串。它將替換結果添加到切片並返回切片,以便讓調用代碼控制內存申請。

舉例:

package main 
import(
    "fmt"
    "regexp"

)

func main() {
    src := []byte(`
        call hello alice
        hello bob
        call hello eve
    `)
    pat := regexp.MustCompile(`(?m)(call)\s+(?P<cmd>\w+)\s+(?P<arg>.+)\s*$`)
    res := []byte{}
    for _, s := range pat.FindAllSubmatchIndex(src, -1){
        res = pat.Expand(res, []byte("$cmd('$arg')\n"), src, s)
    }
    fmt.Println(string(res))
}

返回:

userdeMacBook-Pro:go-learning user$ go run test.go
hello('alice') //
hello('eve')

userdeMacBook-Pro:go-learning user$ 

上面例子使用到的正則表達式語法爲

分組:

        (re)           編號的捕獲分組
        (?P<name>re)   命名並編號的捕獲分組
        (?:re)         不捕獲的分組
        (?flags)       設置當前所在分組的標誌,不捕獲也不匹配
        (?flags:re)    設置re段的標誌,不捕獲的分組

flags的語法爲xyz(設置)、-xyz(清楚)、xy-z(設置xy,清楚z),標誌以下:

        I              大小寫敏感(默認關閉)
        m              ^和$在匹配文本開始和結尾以外,還能夠匹配行首和行尾(默認開啓)
        s              讓.能夠匹配\n(默認關閉)
        U              非貪婪的:交換x*和x*?、x+和x+?……的含義(默認關閉)

所以

  • (?m)表示行首
  • (?P<cmd>\w+)表示將符合\w+(\w== [0-9A-Za-z_])正則表達式的值命名爲name,以後再使用函數時可使用$name來表達

 

其餘函數:

func (*Regexp) Split

func (re *Regexp) Split(s string, n int) []string

Split將re在s中匹配到的結果做爲分隔符將s分割成多個字符串,並返回這些正則匹配結果之間的字符串的切片。

返回的切片不會包含正則匹配的結果,只包含匹配結果之間的片斷。當正則表達式re中不含正則元字符時,本方法等價於strings.SplitN。

參數n絕對返回的子字符串的數量:

n > 0 : 返回最多n個子字符串,最後一個子字符串是剩餘未進行分割的部分。
n == 0: 返回nil (zero substrings)
n < 0 : 返回全部子字符串

舉例:

package main 
import(
    "fmt"
    "regexp"

)

func main() {
    s1 := regexp.MustCompile("a*").Split("abaabaccadaaae", -1) //返回全部值
    fmt.Println(s1) //[ b b c c d e]
    s2 := regexp.MustCompile("a*").Split("abaabaccadaaae", 5) //返回5個值,剩餘的值都寫在最後一個值中
    fmt.Println(s2) //[ b b c cadaaae]
}

 

func QuoteMeta

func QuoteMeta(s string) string

QuoteMeta返回將s中全部正則表達式元字符都進行轉義後字符串。該字符串能夠用在正則表達式中匹配字面值s。例如,QuoteMeta(`[foo]`)會返回`\[foo\]`。

特殊字符有:\.+*?()|[]{}^$ ,這些字符用於實現正則語法,因此看成普通字符使用時須要轉換

 

func (*Regexp) String

func (re *Regexp) String() string

String返回用於編譯成正則表達式的字符串

func (*Regexp) NumSubexp

func (re *Regexp) NumSubexp() int

NumSubexp返回該正則表達式中捕獲分組的數量。

func (*Regexp) SubexpNames

func (re *Regexp) SubexpNames() []string

SubexpNames返回該正則表達式中捕獲分組的名字。第一個分組的名字是names[1],所以,若是m是一個組匹配切片,m[i]的名字是SubexpNames()[i]。由於整個正則表達式是沒法被命名的,names[0]必然是空字符串。該切片不該被修改。

舉例:

package main 
import(
    "fmt"
    "regexp"

)

func main() {
    re := regexp.MustCompile("(?P<first>[a-zA-Z]+) (?P<last>[a-zA-Z]+)")
    fmt.Println(re.String()) //(?P<first>[a-zA-Z]+) (?P<last>[a-zA-Z]+)
    fmt.Println(re.NumSubexp()) //2

    fmt.Println(re.MatchString("Alan Turing")) //true
    fmt.Printf("%q\n", re.SubexpNames()) //["" "first" "last"],分組從索引[1]開始,[0]爲空字符串
    reversed := fmt.Sprintf("${%s} ${%s}", re.SubexpNames()[2], re.SubexpNames()[1]) 
    fmt.Println(reversed) //${last} ${first}
    fmt.Println(re.ReplaceAllString("Alan Turing", reversed)) //Turing Alan,實現先後轉換
}

 

func (*Regexp) LiteralPrefix -返回全部匹配項都共同擁有的前綴(去除可變元素)

func (re *Regexp) LiteralPrefix() (prefix string, complete bool)

LiteralPrefix返回一個字符串字面值prefix,任何匹配本正則表達式的字符串都會以prefix起始。 若是該字符串字面值包含整個正則表達式,返回值complete會設爲真。

complete:若是 prefix 就是正則表達式自己,則返回 true,不然返回 false

舉例:

package main 
import(
    "fmt"
    "regexp"

)

func main() {
    reg := regexp.MustCompile("(?P<first>[a-zA-Z]+) (?P<last>[a-zA-Z]+)")
    prefix, complete := reg.LiteralPrefix()
    fmt.Println(prefix) //匹配項爲空,由於 從頭開始就是可變元素
    fmt.Println(complete)

    reg = regexp.MustCompile(`Hello[\w\s]+`)
    fmt.Println(reg.LiteralPrefix()) //任何字符串要匹配該正則表達式時其必須有前綴Hello,由於前綴不是整個正則,因此爲false
    // Hello false
    reg = regexp.MustCompile(`Hello`)//由於前綴爲整個正則,因此返回true
    fmt.Println(reg.LiteralPrefix())
    // Hello true
}
相關文章
相關標籤/搜索