go标准库的学习-regexp
参考:https://studygolang.com/pkgdoc
导入方式:
- import "regexp"
regexp包实现了正则表达式搜索。
正则表达式采用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,但匹配对象是字符串。
func MatchReader
- func MatchReader(pattern string, r io.RuneReader) (matched bool, err error)
MatchReader类似Match,但匹配对象是io.RuneReader。
举例:
- 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 3] [3 5] [8 10]],-1表示匹配全部
- fmt.Println(re.FindAllStringIndex("paranormal", )) //[[1 3] [3 5]] ,2表示返回匹配的两个的索引切片
- fmt.Println(re.FindAllStringIndex("paranormal", )) //[[1 3]] ,1表示返回匹配的一个的索引切片
- fmt.Println(re.FindAllIndex([]byte("paranormal"), -)) //[[1 3] [3 5] [8 10]]
- fmt.Println(re.FindAllIndex([]byte("paranormal"), )) //[[1 3] [3 5]]
- fmt.Println(re.FindAllIndex([]byte("paranormal"), )) //[[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-"), -)) //[["axxxbyc" "xxx" "y"] ["axxbyc" "xx" "y"] ["axbyc" "x" "y"]]
- fmt.Printf("%q\n", re.FindAllSubmatch([]byte("-axxxbyc-axxbyc-axbyc-"), )) //[["axxxbyc" "xxx" "y"] ["axxbyc" "xx" "y"]]
- fmt.Printf("%q\n", re.FindAllSubmatch([]byte("-axxxbyc-axxbyc-axbyc-"), )) //[["axxxbyc" "xxx" "y"]]
- fmt.Printf("%q\n", re.FindAllSubmatch([]byte("-abzc-abzc-"), -)) //[["abzc" "" "z"] ["abzc" "" "z"]]
- fmt.Printf("%q\n", re.FindAllSubmatch([]byte("-abzc-abzc-"), )) //[["abzc" "" "z"]]
- fmt.Printf("%q\n", re.FindAllSubmatch([]byte("-aczc-"), -)) //[],整个都不匹配,更没有分组匹配,将返回空数组
- fmt.Printf("%q\n", re.FindAllStringSubmatch("-axxxbyc-axxbyc-axbyc-", -)) //[["axxxbyc" "xxx" "y"] ["axxbyc" "xx" "y"] ["axbyc" "x" "y"]]
- fmt.Printf("%q\n", re.FindAllStringSubmatch("-axxxbyc-axxbyc-axbyc-", )) //[["axxxbyc" "xxx" "y"] ["axxbyc" "xx" "y"]]
- fmt.Printf("%q\n", re.FindAllStringSubmatch("-axxxbyc-axxbyc-axbyc-", )) //[["axxxbyc" "xxx" "y"]]
- fmt.Printf("%q\n", re.FindAllStringSubmatch("-abzc-abzc-", -)) //[["abzc" "" "z"] ["abzc" "" "z"]]
- fmt.Printf("%q\n", re.FindAllStringSubmatch("-abzc-abzc-", )) //[["abzc" "" "z"]]
- fmt.Printf("%q\n", re.FindAllStringSubmatch("-aczc-", -)) //[],整个都不匹配,更没有分组匹配,将返回空数组
- }
下面三个函数实现分组匹配查找索引:
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 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-"), )) //[[1 8 2 5 6 7] [9 15 10 12 13 14]]
- fmt.Println(re.FindAllSubmatchIndex([]byte("-axxxbyc-axxbyc-axbyc-"), )) //[[1 8 2 5 6 7]]
- fmt.Println(re.FindAllSubmatchIndex([]byte("-abzc-abzc-"), -)) //[[1 5 2 2 3 4] [6 10 7 7 8 9]]
- fmt.Println(re.FindAllSubmatchIndex([]byte("-abzc-abzc-"), )) //[[1 5 2 2 3 4]]
- fmt.Println(re.FindAllSubmatchIndex([]byte("-aczc-"), -)) //[],整个都不匹配,更没有分组匹配,将返回空数组
- fmt.Println(re.FindAllStringSubmatchIndex("-axxxbyc-axxbyc-axbyc-", -)) //[[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-", )) //[[1 8 2 5 6 7] [9 15 10 12 13 14]]
- fmt.Println(re.FindAllStringSubmatchIndex("-axxxbyc-axxbyc-axbyc-", )) //[[1 8 2 5 6 7]]
- fmt.Println(re.FindAllStringSubmatchIndex("-abzc-abzc-", -)) //[[1 5 2 2 3 4] [6 10 7 7 8 9]]
- fmt.Println(re.FindAllStringSubmatchIndex("-abzc-abzc-", )) //[[1 5 2 2 3 4]]
- fmt.Println(re.FindAllStringSubmatchIndex("-aczc-", -)) //[],整个都不匹配,更没有分组匹配,将返回空数组
- }
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-
- -$-$-
- -${}-${}-
下面两个函数和上面的区别在与当使用$时,不会再将其当作一个简单的字符,而是进行规则替换。了解规则可去看下面的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, -){
- 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 > : 返回最多n个子字符串,最后一个子字符串是剩余未进行分割的部分。
- n == : 返回nil (zero substrings)
- n < : 返回所有子字符串
举例:
- package main
- import(
- "fmt"
- "regexp"
- )
- func main() {
- s1 := regexp.MustCompile("a*").Split("abaabaccadaaae", -) //返回所有值
- fmt.Println(s1) //[ b b c c d e]
- s2 := regexp.MustCompile("a*").Split("abaabaccadaaae", ) //返回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()) //
- fmt.Println(re.MatchString("Alan Turing")) //true
- fmt.Printf("%q\n", re.SubexpNames()) //["" "first" "last"],分组从索引[1]开始,[0]为空字符串
- reversed := fmt.Sprintf("${%s} ${%s}", re.SubexpNames()[], re.SubexpNames()[])
- 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
- }
go标准库的学习-regexp的更多相关文章
- go标准库的学习-net/http
参考:https://studygolang.com/pkgdoc 概念解释: request:用户请求的信息,用来解析用户的请求信息,包括post.get.cookie.url等信息 respons ...
- go标准库的学习-database/sql
参考:https://studygolang.com/pkgdoc 导入方式: import "database/sql" sql包提供了保证SQL或类SQL数据库的泛用接口. 使 ...
- go标准库的学习-crypto/md5
参考:https://studygolang.com/pkgdoc 导入方式: import "crypto/md5" md5包实现了MD5哈希算法,参见RFC 1321. Con ...
- go标准库的学习-crypto/sha1
参考:https://studygolang.com/pkgdoc 导入方式: import "crypto/sha1" sha1包实现了SHA1哈希算法,参见RFC 3174. ...
- go标准库的学习-crypto/sha256
参考:https://studygolang.com/pkgdoc 导入方式: import "crypto/sha256" sha256包实现了SHA224和SHA256哈希算法 ...
- python 标准库基础学习之开发工具部分1学习
#2个标准库模块放一起学习,这样减少占用地方和空间#标准库之compileall字节编译源文件import compileall,re,sys#作用是查找到python文件,并把它们编译成字节码表示, ...
- python calendar标准库基础学习
# -*- coding: utf-8 -*-# 作者:新手__author__ = 'Administrator'#标准库:日期时间基础学习:calendar:处理日期#例1import calen ...
- 《C标准库》学习笔记整理
简介 <C标准库>书中对 C 标准库中的 15 个头文件的内容进行了详细的介绍,包括各头文件设计的背景知识.头文件中的内容.头文件中定义的函数和变量的使用.实现.测试等. 我学习此书的目的 ...
- python linecache标准库基础学习
#python标准库基础之:linecacge:高效读取文本文件#说明与作用"""可以从文件或者导入python模块获取文件,维护一个结果缓存,从而可以更高效地从相同文件 ...
随机推荐
- ajax读取txt文本时乱码的解决方案
前言:第一次学习使用 ajax 就是用来读取文本 先给出现乱码的代码<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional/ ...
- Linux中ssh介绍与ssh+key密钥登陆部署
环境内核信息: [root@zabbix- ~]# uname -a Linux zabbix- -.el6.x86_64 # SMP Tue Mar :: UTC x86_64 x86_64 x86 ...
- [PHP]算法- 二叉树的深度的PHP实现
二叉树的深度: 输入一棵二叉树,求该树的深度.从根结点到叶结点依次经过的结点(含根.叶结点)形成树的一条路径,最长路径的长度为树的深度. 思路: 1.非递归层序遍历 2.使用辅助队列,根结点先入队列 ...
- Docker 安装redis(四)
Docker 安装redis 1.搜索docker镜像(可以看到搜索的结果,这个结果是按照一定的星级评价规则排序的) docker search redis 2.拉取docker的mysql镜像(如果 ...
- elasticsearch6.7 05. Document APIs(6)UPDATE API
5. UPDATE API 更新操作可以使用脚本来更新.更新的时候会先从索引中获取文档数据(在每个分片中的集合),然后运行脚本(使用可选的脚本语言和参数),再果进行索引(还允许删除或忽略该操作).它使 ...
- 如何在表单中使用Ajax
1.HTML就是一个简单表单验证,有登录按钮,点击登录会发送Ajax, 这里就是简单如果用户名为:zhouzhiruo,密码为:123456,就是登录成功,否则登录失败 应该在发送请求之前对input ...
- html 字符串 生成 pdf 完美解决中文不显示
//maven <dependency> <groupId>com.itextpdf</groupId> <artifactId>itextpdf< ...
- 图的遍历(bfs+dfs)模板
bfs #include<iostream> #include<queue> #include<cstdio> using namespace std; queue ...
- wepy里面两种不同的写回调函数的方法
方案一const getHelpCenter = createAction(GET_HELP_CENTER, () => request('api/hisense/article/menu/li ...
- 语义分割的简单指南 A Simple Guide to Semantic Segmentation
语义分割是将标签分配给图像中的每个像素的过程.这与分类形成鲜明对比,其中单个标签被分配给整个图片.语义分段将同一类的多个对象视为单个实体.另一方面,实例分段将同一类的多个对象视为不同的单个对象(或实例 ...