算法第四版部分章节总结,熟悉正则表达式,需知正则描述模式和正则常用缩略写法。
一、正则描述模式
二、正则缩略写法 (闭包简写,字符集,元字符)
三、正则实践 (字符串查找,字符串替换,网页标签匹配)
正则表示式,就是在一个字符串之中查找满足要求的子字符串
连接操作
连接操作就是匹配连接后的结果
有 hello和 go 两个单词将它们连接起来,用正则表式为 (hello)(go),就是连接操作,如果正则有了,但是字符串只有hello是匹配不会成功的,必须满足匹配规则的全部要求
连接操作匹配一个邮箱 (示例:[email protected])
操作 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|
拆分成 | 邮箱名 abcabc | 小老鼠 @ | 服务商域名 qq | 点 . | 国际域名 com |
对应正则 | [\w]{5,15} | @ | [\w]+ | . | [a-zA-Z]{2,14} |
完整的正则 : [\w]{5,15}@[\w]+\.[a-zA-Z]+
连接操作取出网页中的价格 (< div>< span class=“price”> 55.9< /span>< /div>)
操作 | 1 | 2 | 3 |
---|---|---|---|
拆分 | 55.9 | ||
对应正则 | \ | [\d\.] | \ |
完整正则 \[\d\.]+\
,
以上结果会取到这一整个标签,需要把这个匹配结果二次操作,取出其中的价格 [\d\.]+
或操作
或操作就是指定多个匹配结果,
与程序中的 | or 相似,满足其中一个条件就可以了。例如手机号码的匹配,常用号码由13 15 17 18 19 开头,用正则写匹配开头2位 (13|15|17|18|19),或操作用括号包起来,因为这是整个表示式中的其中一个整体,后面的9位[0-9]{9},
连起来就是 (13|15|17|18|19)[0-9]{9}
闭包操作
闭包就是把一个匹配规则重复任意次数,
注册一个用户名,长度可能5位,也可以8位、15位,闭包就可以多次匹配,如[a-z] 默认只匹配一次,匹配结果是a-z中的一个字母,使用闭包操作就是 [a-z]+,那么它将会匹配1次到无数次,因为闭包操作中 + 的匹配字数是至少 1 次。
闭包有以下几种操作, 详细说明见下闭包的简写
? + * {}
但凡涉及到这几个操作符号的 那么就有包含闭包,有 | 号的就是包括或操作,有连接的就是包括连接操作,正则之中这三种操作是重点。
括号
使用括号来改变默认的优先级顺序,与程序中的()是一样一样的,
例如
X(A|B)Z ,匹配的结果 [XAZ, XBZ] ,
*X|A|B|Z,无括号匹配的结果 [X, A, B, Z] *
X|(A|B|Z) ,匹配结果 [XA,XB,XZ],
(X|Y)(A|B)C,匹配结果 [XAC, XBC, YAC, YBC]
就像我们力求写出最简洁的程序和高效的算法 一样,避免表达式冗余
字符集
通配符,匹配任意一个字符,中括号内的字符表示匹配其中的任意一个,范围集合,指定的范围内的字符,补集即括号内以外的任意字符
名称 | 记法 | 示例 |
---|---|---|
通配符 | . 匹配除换行符以外的任意字符 |
abc., |
范围集合 | 用[]包括,指定某一范围内的值 用 - 来表示 | [0-9][0-5][a-z] |
指定集合 | 用[]包括,指定在为某几个值 | [aeiou]* |
补集 | 用[]包含,首字符为 ^ | [^aeiou]* |
闭包的简写
闭包的意思是把一个操作复制任意次数,?号一次或者0次,+号一次或者多次,*号0次或者多次,{}指定次数
闭包以下几种操作,
符号 | 匹配的字符长度 |
---|---|
? | 一个或者 0 次 |
+ | 一次或者多次 |
* | 0次或者多次 |
{n} | 指定重复次数等于 n |
{n,m} | 次数 n 到 m , 示例: {1,5} 1-5次。{2,}至少2次 , {,5}最多5次 |
转义序列
*
?
.
+
/
是正则中的元字符,在它们前面加转义符号\
,它们就是没有语义的普通字符
*
在正则中是匹配0或无数次,\*
则表示一个普通的字符*,
\
表示转义 \\
则表示一个普通字符\,
还有一些特殊字符, \t制表符,\n换行符, \s空白字符, \d数字
常用元字符
代码 | 说明 | |
---|---|---|
. | 匹配除换行符以外的任意字符 | 除“\n”之外的任何单个字符 |
\w | 匹配字母或数字或下划线 | 等价于“[A-Za-z0-9_]”。 |
\s | 匹配任意的空白符 | 等价于 [ \f\n\r\t\v] |
\d | 匹配数字 | 等价于[0-9] |
\b | 匹配单词的开始或结束 | 单词 never, ne\b可以匹配到ne, er\b 可以匹配到er,但不能匹配 verb 中的er |
^ | 匹配字符串的开始 | |
$ | 匹配字符串的结束 |
其它元字符
\f 匹配一个换页符。等价于 \x0c 和 \cL。
\n 匹配一个换行符。等价于 \x0a 和 \cJ。
\r 匹配一个回车符。等价于 \x0d 和 \cM。
\t 匹配一个制表符。等价于 \x09 和 \cI。
\v 匹配一个垂直制表符。等价于 \x0b 和 \cK。
大写元字符匹配结果与小写元字符相反,示例: \W, \S, \D, \B ,等于 [^\w] ,[\s],[\d],[^\b]
正则表达式, 在编写处理字符串的程序或网页时,经常有查找符合某些复杂规则的字符串的需要。正则表达式就是用于描述这些规则的工具。换句话说,正则表达式就是记录文本规则的代码。
正则在线测试: http://tool.chinaz.com/regex/
go语言正则表达式查找字符串示例
package main
import(
"regexp"
"fmt"
)
func main() {
text :="Abc a7c MFC 8ca. 你好! Golang/"
//查找连续的小写字母
reg := regexp.MustCompile(`[a-z]{2,}`)
fmt.Printf("%s\n", reg.FindAllString(text, -1))// [bc ca olang]
}
查找连续的非小写字母
reg = regexp.MustCompile(`[^a-z]{2,}`)
fmt.Printf("%s\n",reg.FindAllString(text, -1))//[ MFC 8 . 你好! G]
查找连续的单词字母
reg = regexp.MustCompile(`[a-zA-Z]{2,}`)
fmt.Printf("%s\n", reg.FindAllString(text, -1))//[Abc MFC ca Golang]
查找连续的非单词字母、非空白字符
reg = regexp.MustCompile(`[^a-zA-Z\s]+`)
fmt.Printf("%s\n", reg.FindAllString(text, -1)) //[7 8 . 你好! /]
查找连续的大写字母
reg = regexp.MustCompile(`[A-Z]+`)
fmt.Printf("%s\n", reg.FindAllString(text, -1)) //[A MFC G]
查找 abc 或 Golang
reg = regexp.MustCompile(`(abc|Golang)`)
fmt.Printf("%s\n", reg.FindAllString(text, -1)) //[Golang]
查找以 G开头,以 / 结尾的单词
reg = regexp.MustCompile(`G[\w.]*\/`)
fmt.Printf("%s\n", reg.FindAllString(text, -1)) //[Golang/]
查找从行首开始,以空格结尾的字符串
reg = regexp.MustCompile(`[\w]+\s`)
fmt.Printf("%s\n", reg.FindAllString(text, -1)) //[Abc a7c MFC ]
查找连续 1 次到 4 次的非空格字符,并以 c 结尾的字符串
reg = regexp.MustCompile(`[^\s]{1,4}c`)
fmt.Printf("%s\n", reg.FindAllString(text, -1)) //[Abc a7c 8c]
go语言正则表达式字符串替换示例
package main
import(
"regexp"
"fmt"
)
func main() {
text :="Abc a7c MFC 8ca. 你好! Golang/"
// 查找 Abc 或 a7c,替换为 Abccc a7ccc
reg = regexp.MustCompile(`(Ab|a7)c`)
fmt.Printf("%q\n", reg.ReplaceAllString(text, `${1}ccc`)) //"Abccc a7ccc MFC 8ca. 你好! Golang/"
}
查找 Abc 或 a7c 或 你好 ,替换为**号
reg = regexp.MustCompile(`(Abc|a7c|你好)`)
fmt.Printf("%s\n", reg.ReplaceAllString(text, "**")) //** ** MFC 8ca. **! Golang/
在每个单词后面加上 , 号
reg = regexp.MustCompile(`([\w.]+)\s`)
fmt.Printf("%s\n", reg.ReplaceAllString(text, "${1},")) //Abc,a7c,MFC,8ca.,你好! Golang/
把 a 开头的单词 更改成大写 A
reg = regexp.MustCompile(`[a](\w.)`)
fmt.Printf("%s\n", reg.ReplaceAllString(text, `A${1}`)) //Abc A7c Aa MFC 8ca. 你好! GolAng/
交换 Abc 和 Golang
reg = regexp.MustCompile(`(Abc)(.*)(Golang)`)
fmt.Printf("%s\n", reg.ReplaceAllString(text, `${3}${2}${1}`)) //Golang a7c MFC 8ca. 你好! Abc/
go语言 正则表达式 获取网页标签内的数据 示例
package main
import(
"regexp"
"fmt"
"io/ioutil"
)
func main() {
//读取文件
f,err := ioutil.ReadFile("./spider-page/regexp-1A0001.html")
if err != nil {
fmt.Print(err)
}
str := string(f)
//获取 标题内的文字
reg := regexp.MustCompile(`(?s:(.*?))(.*)`)
text := reg.FindAllStringSubmatch(str, -1)
fmt.Printf("%s-%s\n",text[0][1],text[0][2]) // 上证指数-1A0001
}
获取今天最低价格
reg = regexp.MustCompile(`(?s:(.*?))`)
text = reg.FindAllStringSubmatch(str, -1)
fmt.Printf("最低价:%s\n",text[0][1]) // 最低价:2533.36
获取今天最高价格
reg = regexp.MustCompile(`(?s:(.*?))`)
text = reg.FindAllStringSubmatch(str, -1)
fmt.Printf("最高价:%s\n",text[0][1]) // 最高价:2554.79
获取当前时间
reg = regexp.MustCompile(`(?s:(.*?))`)
text = reg.FindAllStringSubmatch(str, -1)
fmt.Printf("当前价:%s\n",text[0][1]) // 当前价:2553.83
获取当前价格
reg = regexp.MustCompile(`(?s:(.*?))
`)
text = reg.FindAllStringSubmatch(str, -1)
fmt.Printf("当前时间:%s\n",text[0][1]) // 当前时间:2019年1月12日 15:00:00
返回结果
上证指数-1A0001
最低价:2533.36
最高价:2554.79
当前价:2553.83
当前时间:2019年1月12日 15:00:00
regexp-1A0001.html(示例文件)
上证指数1A0001
-
今开:2539.55
成交量:149.4亿
振幅:0.85%
-
最高:2554.79
成交额:1223.8亿
换手:0.45%
-
最低:2533.36
总市值:276895.2亿
市净率:0
-
昨收:2535.10
流通市值:238534.6亿
市盈率(动):亏损