Go 正则匹配之跨行匹配

2023-12-29 20:28
文章标签 go 匹配 正则 跨行

本文主要是介绍Go 正则匹配之跨行匹配,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

跨行匹配

一般正则匹配默认是按行来进行匹配的,如果要跨行匹配,需要使用 `(?s)` 来启用多行模式。

package mainimport ("fmt""regexp"
)func main() {data := "This is the first line. \nAnd this is the second line."// fmt.Println(data)// re := regexp.MustCompile(`line.*And`)re := regexp.MustCompile(`(?s)line.*And`)match := re.FindString(data)fmt.Println(match)out := re.ReplaceAllString(data, "------")fmt.Println(out)
}
line. 
And
This is the first ------ this is the second line.

go 正则匹配相关的其他常用函数

Compile、MustCompile

同样的功能,不同的设计:

  1. Compile函数基于错误处理设计,将正则表达式编译成有效的可匹配格式,适用于用户输入场景。当用户输入的正则表达式不合法时,该函数会返回一个错误。
  2. MustCompile函数基于异常处理设计,适用于硬编码场景。当调用者明确知道输入不会引起函数错误时,要求调用者检查这个错误是不必要和累赘的。我们应该假设函数的输入一直合法,当调用者输入了不应该出现的输入时,就触发panic异常。

其实直接从 MustCompile 的实现可以看出,MustCompile 本质上是调用的 Compile ,如果表达式编译失败,直接 panic ,而 Compile 则会把 err 返回,由用户决定是否 panic 或进行其他处理:

// MustCompile is like Compile but panics if the expression cannot be parsed.
// It simplifies safe initialization of global variables holding compiled regular
// expressions.
func MustCompile(str string) *Regexp {regexp, err := Compile(str)if err != nil {panic(`regexp: Compile(` + quote(str) + `): ` + err.Error())}return regexp
}

FindString

FindString 用来返回匹配到的第一个字符串。

package mainimport ("fmt""regexp"
)func main() {data := "This is the first line. \nAnd this is the second line."re := regexp.MustCompile(`the .* line`)match := re.FindString(data)fmt.Println(match) // the first line
}

FindAllString

FindString 用来返回匹配到的所有的字符串。用户可以指定想要返回的匹配到的字符串的个数。

package mainimport ("fmt""regexp"
)func main() {data := "This is the first line. \nAnd this is the second line."re := regexp.MustCompile(`the .* line`)match := re.FindAllString(data, 3)fmt.Printf("%#v\n", match) // []string{"the first line", "the second line"}
}

Find

类似于FindString,只不过以字节数组的形式表示。

package mainimport ("fmt""regexp"
)func main() {data := "This is the first line. \nAnd this is the second line."re := regexp.MustCompile(`the .* line`)match := re.Find([]byte(data))// match := re.FindAll([]byte(data), 3)fmt.Printf("%#v\n", match)         // []byte{0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x6c, 0x69, 0x6e, 0x65}fmt.Printf("%#v\n", string(match)) // "the first line"
}

FindAll

package mainimport ("fmt""regexp"
)func main() {data := "This is the first line. \nAnd this is the second line."re := regexp.MustCompile(`the .* line`)// match := re.Find([]byte(data))match := re.FindAll([]byte(data), 3)fmt.Printf("%#v\n", match) // [][]uint8{[]uint8{0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x6c, 0x69, 0x6e, 0x65}, []uint8{0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x6c, 0x69, 0x6e, 0x65}}
}

FindIndex

返回匹配字符串的起始位置和结束位置索引,未匹配到的话返回 nil

package mainimport ("fmt""regexp"
)func main() {data := "This is the first line. \nAnd this is the second line."re := regexp.MustCompile(`the .* line`)match := re.FindIndex([]byte(data))// match := re.FindAll([]byte(data), 3)fmt.Printf("%#v\n", match)                   // []int{8, 22}if match == nil {fmt.Println("match is nil")return}fmt.Printf("%#v\n", data[match[0]:match[1]]) // "the first line"
}

临时插入一个小知识,声明一个未初始化的 Array 或 Map ,其值初始为 nil。

package mainimport ("fmt"
)func main() {var a []intfmt.Printf("%#v\n", a) // []int(nil)fmt.Println(a == nil)  // truea = []int{}fmt.Printf("%#v\n", a) // []int{}fmt.Println(a == nil)  // falsevar m map[string]stringfmt.Printf("%#v\n", m) // map[string]string(nil)fmt.Println(m == nil)  // truem = map[string]string{}fmt.Printf("%#v\n", m) // map[string]string{}fmt.Println(m == nil)  // false
}

FindAllIndex

package mainimport ("fmt""regexp"
)func main() {data := "This is the first line. \nAnd this is the second line."re := regexp.MustCompile(`the .* line`)match := re.FindAllIndex([]byte(data), 3)// match := re.FindAll([]byte(data), 3)fmt.Printf("%#v\n", match) // [][]int{[]int{8, 22}, []int{37, 52}}if match == nil {fmt.Println("match is nil")return}for _, m := range match {fmt.Printf("%#v\n", data[m[0]:m[1]]) // "the first line"  "the second line"}
}

FindSubMatch

有些例子比较简单,就不多描述了

package mainimport ("fmt""regexp"
)func main() {data := "This is the first line. \nAnd this is the second line."re := regexp.MustCompile(`the .* line`)match := re.FindSubmatch([]byte(data))fmt.Printf("%#v\n", match) // [][]uint8{[]uint8{0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x6c, 0x69, 0x6e, 0x65}}
}

FindAllSubMatch

package mainimport ("fmt""regexp"
)func main() {data := "This is the first line. \nAnd this is the second line."re := regexp.MustCompile(`the .* line`)match := re.FindAllSubmatch([]byte(data), 3)fmt.Printf("%#v\n", match) // [][][]uint8{[][]uint8{[]uint8{0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x6c, 0x69, 0x6e, 0x65}}, //             [][]uint8{[]uint8{0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x6c, 0x69, 0x6e, 0x65}}}
}

FindStringSubMatch

package mainimport ("fmt""regexp"
)func main() {data := "This is the first line. \nAnd this is the second line."re := regexp.MustCompile(`the .* line`)match := re.FindStringSubmatch(data)fmt.Printf("%#v\n", match) // []string{"the first line"}
}

FindAllStringSubMatch

package mainimport ("fmt""regexp"
)func main() {data := "This is the first line. \nAnd this is the second line."re := regexp.MustCompile(`the .* line`)match := re.FindAllStringSubmatch(data, 3)fmt.Printf("%#v\n", match) // [][]string{[]string{"the first line"}, []string{"the second line"}}
}

ReplaceAllString

将所有匹配到的字符串使用给定字符串进行替换。替换的字符可以引用匹配组的内容。

package mainimport ("fmt""regexp"
)func main() {data := "This is the first line. \nAnd this is the second line."re := regexp.MustCompile(`the (.*) line`)out := re.ReplaceAllString(data, "$1") fmt.Printf("%#v\n", out) // "This is first. \nAnd this is second."
}

ReplaceAllFunc 

package mainimport ("fmt""regexp"
)func main() {data := "This is the first line. \nAnd this is the second line."re := regexp.MustCompile(`the .* line`)out := re.ReplaceAllFunc([]byte(data), func(bytes []byte) []byte {return []byte("[" + string(bytes) + "]")})fmt.Printf("%#v\n", out)         // []byte{0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x5b, 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x5d, 0x2e, 0x20, 0xa, 0x41, 0x6e, 0x64, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x5b, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x5d, 0x2e}fmt.Printf("%#v\n", string(out)) // "This is [the first line]. \nAnd this is [the second line]."
}

ReplaceAllStringFunc

可以编写函数来决定如何替换掉匹配到的字符串,其中匿名函数中参数 s 为匹配到的字符串。

package mainimport ("fmt""regexp"
)func main() {data := "This is the first line. \nAnd this is the second line."re := regexp.MustCompile(`the .* line`)out := re.ReplaceAllStringFunc(data, func(s string) string {return "[" + s + "]"})fmt.Printf("%#v\n", out) // "This is [the first line]. \nAnd this is [the second line]."
}

ReplaceAllLiteral

通过字面量替换,以字节数组的形式。

package mainimport ("fmt""regexp"
)func main() {data := "This is the first line. \nAnd this is the second line."re := regexp.MustCompile(`the (.*) line`)out := re.ReplaceAllLiteral([]byte(data), []byte("$1"))fmt.Printf("%#v\n", out)         // []byte{0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x24, 0x31, 0x2e, 0x20, 0xa, 0x41, 0x6e, 0x64, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x24, 0x31, 0x2e}fmt.Printf("%#v\n", string(out)) // "This is $1. \nAnd this is $1."
}

ReplaceAllLiteralString

替换的字符串被当作字符串字面量进行处理。

package mainimport ("fmt""regexp"
)func main() {data := "This is the first line. \nAnd this is the second line."re := regexp.MustCompile(`the (.*) line`)out := re.ReplaceAllLiteralString(data, "$1")fmt.Printf("%#v\n", out) // "This is $1. \nAnd this is $1."
}

ReplaceAll

package mainimport ("fmt""regexp"
)func main() {data := "This is the first line. \nAnd this is the second line."re := regexp.MustCompile(`the .* line`)out := re.ReplaceAll([]byte(data), []byte("---replace string---"))fmt.Printf("%#v\n", out)         // []byte{0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x2d, 0x2d, 0x2d, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2d, 0x2d, 0x2d, 0x2e, 0x20, 0xa, 0x41, 0x6e, 0x64, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x2d, 0x2d, 0x2d, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2d, 0x2d, 0x2d, 0x2e}fmt.Printf("%#v\n", string(out)) // "This is ---replace string---. \nAnd this is ---replace string---."
}

MatchString

正则模式是否有匹配到字符串。

package mainimport ("fmt""regexp"
)func main() {data := "This is the first line. \nAnd this is the second line."re := regexp.MustCompile(`the .* line`)match := re.MatchString(data)fmt.Printf("%#v\n", match) // truere = regexp.MustCompile(`the x.* line`)match = re.MatchString(data)fmt.Printf("%#v\n", match) // false
}

Match

package mainimport ("fmt""regexp"
)func main() {data := "This is the first line. \nAnd this is the second line."re := regexp.MustCompile(`the .* line`)match := re.Match([]byte(data))fmt.Printf("%#v\n", match) // truere = regexp.MustCompile(`the x.* line`)match = re.Match([]byte(data))fmt.Printf("%#v\n", match) // false
}

Split

将正则匹配到的字符串作为分隔符,对原字符串进行 Split 分隔,返回分隔后生成的数据。用户可以指定分隔后数组的长度(不超过全部分隔后的数组长度)。

package mainimport ("fmt""regexp"
)func main() {data := "This is the first line. \nAnd this is the second line."re := regexp.MustCompile(`the .* line`)out := re.Split(data, 1)fmt.Printf("%#v\n", out) // []string{"This is the first line. \nAnd this is the second line."}out = re.Split(data, 2)fmt.Printf("%#v\n", out) // []string{"This is ", ". \nAnd this is the second line."}out = re.Split(data, 3)fmt.Printf("%#v\n", out) // []string{"This is ", ". \nAnd this is ", "."}out = re.Split(data, 4)fmt.Printf("%#v\n", out) // []string{"This is ", ". \nAnd this is ", "."}
}

NumSubexp

返回正则模式子组的数目

package mainimport ("fmt""regexp"
)func main() {// data := "This is the first line. \nAnd this is the second line."re := regexp.MustCompile(`the (.*) lin()e`)// out := re.FindString(data)// fmt.Printf("%#v\n", out)fmt.Printf("%#v\n", re.NumSubexp()) // 2
}

LiteralPrefix

返回所有匹配项都共同拥有的前缀(去除可变元素)

prefix:共同拥有的前缀

complete:如果 prefix 就是正则表达式本身,则返回 true,否则返回 false

package mainimport ("fmt""regexp"
)func main() {// data := "This is the first line. \nAnd this is the second line."re := regexp.MustCompile(`the (.*) line`)prefix, complete := re.LiteralPrefix()fmt.Printf("%#v\n", prefix)   // "the "fmt.Printf("%#v\n", complete) // falsere = regexp.MustCompile(`the line`)prefix, complete = re.LiteralPrefix()fmt.Printf("%#v\n", prefix)   // "the line"fmt.Printf("%#v\n", complete) // true
}

这篇关于Go 正则匹配之跨行匹配的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/550613

相关文章

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

hdu 3065 AC自动机 匹配串编号以及出现次数

题意: 仍旧是天朝语题。 Input 第一行,一个整数N(1<=N<=1000),表示病毒特征码的个数。 接下来N行,每行表示一个病毒特征码,特征码字符串长度在1—50之间,并且只包含“英文大写字符”。任意两个病毒特征码,不会完全相同。 在这之后一行,表示“万恶之源”网站源码,源码字符串长度在2000000之内。字符串中字符都是ASCII码可见字符(不包括回车)。

二分最大匹配总结

HDU 2444  黑白染色 ,二分图判定 const int maxn = 208 ;vector<int> g[maxn] ;int n ;bool vis[maxn] ;int match[maxn] ;;int color[maxn] ;int setcolor(int u , int c){color[u] = c ;for(vector<int>::iter

Go Playground 在线编程环境

For all examples in this and the next chapter, we will use Go Playground. Go Playground represents a web service that can run programs written in Go. It can be opened in a web browser using the follow

POJ 3057 最大二分匹配+bfs + 二分

SampleInput35 5XXDXXX...XD...XX...DXXXXX5 12XXXXXXXXXXXXX..........DX.XXXXXXXXXXX..........XXXXXXXXXXXXX5 5XDXXXX.X.DXX.XXD.X.XXXXDXSampleOutput321impossible

go基础知识归纳总结

无缓冲的 channel 和有缓冲的 channel 的区别? 在 Go 语言中,channel 是用来在 goroutines 之间传递数据的主要机制。它们有两种类型:无缓冲的 channel 和有缓冲的 channel。 无缓冲的 channel 行为:无缓冲的 channel 是一种同步的通信方式,发送和接收必须同时发生。如果一个 goroutine 试图通过无缓冲 channel

如何确定 Go 语言中 HTTP 连接池的最佳参数?

确定 Go 语言中 HTTP 连接池的最佳参数可以通过以下几种方式: 一、分析应用场景和需求 并发请求量: 确定应用程序在特定时间段内可能同时发起的 HTTP 请求数量。如果并发请求量很高,需要设置较大的连接池参数以满足需求。例如,对于一个高并发的 Web 服务,可能同时有数百个请求在处理,此时需要较大的连接池大小。可以通过压力测试工具模拟高并发场景,观察系统在不同并发请求下的性能表现,从而

【Go】go连接clickhouse使用TCP协议

离开你是傻是对是错 是看破是软弱 这结果是爱是恨或者是什么 如果是种解脱 怎么会还有眷恋在我心窝 那么爱你为什么                      🎵 黄品源/莫文蔚《那么爱你为什么》 package mainimport ("context""fmt""log""time""github.com/ClickHouse/clickhouse-go/v2")func main(

OmniGlue论文详解(特征匹配)

OmniGlue论文详解(特征匹配) 摘要1. 引言2. 相关工作2.1. 广义局部特征匹配2.2. 稀疏可学习匹配2.3. 半稠密可学习匹配2.4. 与其他图像表示匹配 3. OmniGlue3.1. 模型概述3.2. OmniGlue 细节3.2.1. 特征提取3.2.2. 利用DINOv2构建图形。3.2.3. 信息传播与新的指导3.2.4. 匹配层和损失函数3.2.5. 与Super

二分图的最大匹配——《啊哈!算法》

二分图 如果一个图的所有顶点可以被分为X和Y两个集合,并且所有边的两个顶点恰好一个属于X,另外一个属于Y,即每个集合内的顶点没有边相连,那么此图就是二分图。 二分图在任务调度、工作安排等方面有较多的应用。 判断二分图:首先将任意一个顶点着红色,然后将其相邻的顶点着蓝色,如果按照这样的着色方法可以将全部顶点着色的话,并且相邻的顶点着色不同,那么该图就是二分图。 java