[TOC]
# re库正则表达式的基础使用
> 正则表达式的好处就是可以通过简短表达式精准表达需要匹配内容,然后在文本数据中快速匹配提取到需要的文本内容。
正则表达式可以很简短,也可以很复杂,可能对于同一个结果,不同人写出来的表达式也是千差万别。
为了能够写出优雅的正则表达式,我们首先了解一下它的语法信息,在不断练习实践,才能达到了熟练使用正则表达式的效果。
## 正则表达式语法
> 为了方便理解记忆,下面将正则表达式进行了归类整理。
### 元字符含义
| 元字符 | 含义 |
| :----- | :-------------------- |
| . | (点) 在默认模式,匹配除了换行的任意字符。如果指定了标签 DOTALL ,它将匹配包括换行符的任意字符。 |
| \\ | 转义特殊字符(允许你匹配 '*', '?', 或者此类其他),或者表示一个特殊序列; 为了防止`反斜杠灾难`,推荐无论多简单的表达式都要使用 r(raw) 原生字符串来表达,例如: r"\\w.*" |
| [] | 用于表示一个字符集合。比如 [amk] 匹配 'a', 'm', 或者 'k'。 可以表示字符范围,通过用 '-' 将两个字符连起来。 比如 [a-z] 将匹配任何小写ASCII字符. 特殊字符在集合中,失去它的特殊含义。比如 [(+*)] 只会匹配这几个文法字符 '(', '+', '*', or ')'。 字符类如 \w 或者 \S (如下定义) 在集合内可以接受,它们可以匹配的字符由 ASCII 或者 LOCALE 模式决定。 '^'字符放在开始位置表示取反操作,例如 [^5] 将匹配所有字符,除了 '5',但是 [5^] 将匹配 '5' 或 '^'。 在集合内要匹配一个字符 ']',有两种方法,要么就在它之前加上反斜杠,要么就把它放到集合首位。比如, [()[\]{}] 和 []()[{}] 都可以匹配括号。 |
| \| | A\|B, A 和 B 可以是任意正则表达式,创建一个正则表达式,匹配 A 或者 B. 任意个正则表达式可以用 '\|' 连接。它也可以在组合(见下列)内使用。扫描目标字符串时, '\|' 分隔开的正则样式从左到右进行匹配。当一个样式完全匹配时,这个分支就被接受。意思就是,一旦 A 匹配成功, B 就不再进行匹配,即便它能产生一个更好的匹配。或者说,'\|' 操作符绝不贪婪。 如果要匹配 '\|' 字符,使用 \\\|, 或者把它包含在字符集里,比如 [\|]. |
### 重复匹配
| 元字符 | 含义 |
| :---- | :------------- |
| * | 对它前面的正则式匹配0到任意次重复, 尽量多的匹配字符串。 ab* 会匹配 'a', 'ab', 或者 'a'``后面跟随任意个 ``'b'。 |
| + | 对它前面的正则式匹配1到任意次重复。 ab+ 会匹配 'a' 后面跟随1个以上到任意个 'b',它不会匹配 'a'。 |
| ? | 对它前面的正则式匹配0到1次重复。 ab? 会匹配 'a' 或者 'ab'。 |
| *?, +?, ?? | **非贪婪模式匹配**,字符串'abc'在使用正则式 <.*?>时 将会仅仅匹配 '<a>'。 |
| {m} | 对其之前的正则式指定匹配 m 个重复;少于 m 的话就会导致匹配失败。比如, a{6} 将匹配6个 'a' , 但是不能是5个。 |
| {m,n} | 对正则式进行 m 到 n 次匹配,在 m 和 n 之间取尽量多。 比如,a{3,5} 将匹配 3 到 5个 'a'。忽略 m 意为指定下界为0,忽略 n 指定上界为无限次。 比如 a{4,}b 将匹配 'aaaab' 或者1000个 'a' 尾随一个 'b',但不能匹配 'aaab'。逗号不能省略,否则无法辨别修饰符应该忽略哪个边界。 |
| {m,n}? | 前一个修饰符的**非贪婪模式**,只匹配尽量少的字符次数。比如,对于 'aaaaaa', a{3,5} 匹配 5个 'a' ,而 a{3,5}? 只匹配3个 'a'。 |
### 边界匹配
| 元字符 | 含义 |模式示例 |匹配成功 | 匹配失败 |
| :------ | :------------- |:--------- |:--------- |:-------- |
| ^ | 匹配字符串开始,并且在 MULTILINE 模式也匹配换行后的首个符号。 | ^ABC | ABC | abcABC |
| $ | 匹配字符串末尾,在 MULTILINE 模式匹配换行符的前一个字符。 | ABC\$ | abcABC | abcdABCD|
| \A | 只匹配字符串开始。 | ^ABC | ABC | abcABC |
| \Z | 只匹配字符串末尾。 | ABC$ | xABC | xABCD|
| \b | 单词边界匹配,匹配空字符串,但只在单词开始或结尾的位置。 | r\bfoo\b | 'foo','foo.' | 'abcfooxyz', 'foo3' |
| \B | 匹配空字符串,但不能在词的开头或者结尾。 与\b语义相反。 | r'py\B' | 'python','py3' | 'py','py.' |
| \d | Unicode下匹配数字0-9和其他数字符号,ASCII下匹配0-9的数字。 | r'A\dC' | 'A2C' | 'ABC' |
| \D | 匹配任何非十进制数字的字符。就是 \d 取非。 | r'A\DC' | 'ABC' | 'A2C' |
| \s | 匹配ASCII中的空白字符,就是 [ \t\n\r\f\v] | r'bob\sis' | 'bob is ...' | 'bobisaboy' |
| \S | 匹配任何非空白字符。就是 \s 取非。如果设置了 ASCII 标志,就相当于 [^ \t\n\r\f\v] 。 | r'(\S+)\s+(\S+)' | 'hello world' | 'helloworld' |
| \w | 匹配Unicode词语的字符,包含了可以构成词语的绝大部分字符,也包括数字和下划线。如果设置了 ASCII 标志,就只匹配 [a-zA-Z0-9_] 。 匹配ASCII字符中的数字和字母和下划线,就是 [a-zA-Z0-9_] 。如果设置了 LOCALE 标记,就匹配当前语言区域的数字和字母和下划线。 | r'\b\w+\b' | 'adkfa' | '[]' ,'&' |
| \W | 匹配非单词字符的字符。这与 \w 正相反。如果使用了 ASCII 旗标,这就等价于 [^a-zA-Z0-9_]。如果使用了 LOCALE 旗标,则会匹配当前区域中既非字母数字也非下划线的字符。 | r'name\Wvalue' | 'name=value' | 'name_value'|
### 分组
| 元字符 | 含义 |模式示例 |匹配成功 | 匹配失败 |
| :------ | :------------- |:--------- |:--------- |:-------- |
| (...) | (组合),匹配括号内的任意正则表达式,并标识出组合的开始和结尾。匹配完成后,组合的内容可以被获取,并可以在之后用 \\number 转义序列进行再次匹配,之后进行详细说明。要匹配字符 '(' 或者 ')', 用 \\( 或 \\), 或者把它们包含在字符集合里: [(], [)]. | r'1(abc\|xyz)2' | '1abc2','1xyz2' | '1abcxyz2' |
|(?P\<name\>) | (命名组合)类似正则组合,但是匹配到的子串组在外部是通过定义的 name 来获取的。 | (?P\<quote>['"]).*?(?P=quote) |"xyz"|abc(无引号)|
| (?P=name) | 引用别名为name的分组字符串 |(?P\<quote>['"]).*?(?P=quote) |"xyz"|abc(无引号)|
| \\number | 引用编号为<number>的分组字符串 | (['"]).*?\1 |"xyz"|abc(无引号)|
### 特殊组合(使用()表达式但是却不作为分组获取)
| 元字符 | 含义 |模式示例 |匹配成功 | 匹配失败 |
| :------ | :------------- |:--------- |:--------- |:-------- |
|(?:…) |正则括号的非捕获版本。 匹配在括号内的任何正则表达式,但该分组所匹配的子字符串 不能 在执行匹配后被`获取`或是之后在模式中被`引用`。这是与(...) 分组之间的区别。例如这样使用是错误的r'(?:abc)\\1'| r'(?i)(http://.*?(?:jpg|png|jpeg))'| 'http:xxx.xxx/1001.jpg' | 'http:xxx.xxx/1002.svg' |
| (?aiLmsux)|( 'a', 'i', 'L', 'm', 's', 'u', 'x' 中的一个或多个) 这个组合匹配一个空字符串;这些字符对正则表达式设置以下标记 re.A (只匹配ASCII字符), re.I (忽略大小写), re.L (语言依赖), re.M (多行模式), re.S (点dot匹配全部字符), re.U (Unicode匹配), and re.X (冗长模式)。 (这些标记在 模块内容 中描述) 如果你想将这些标记包含在正则表达式中,这个方法就很有用,免去了在 re.compile() 中传递 flag 参数。标记应该在表达式字符串首位表示。 |r'(?i)abc' |Abc | axbc |
|(?#…) | 注释;里面的内容会被忽略。| name(?#this is a comment)=123 | name=123 | namexxxx |
|(?=…) |匹配 … 的内容,但是并不消费样式的内容。这个叫做 lookahead assertion。 | Isaac (?=Asimov)|IsaacAsimov | Isaac|
|(?!…) |匹配 … 不符合的情况。这个叫 negative lookahead assertion (前视取反)。 | Isaac (?!Asimov)| Isaac| IsaacAsimov|
|(?\<=…) |匹配字符串的当前位置,它的前面匹配 … 的内容到当前位置。这叫:dfn:positive lookbehind assertion (正向后视断定)。**注意以 positive lookbehind assertions 开始的样式,如 (?<=abc)def ,并不是从 a 开始搜索,而是从 d 往回看的。你可能更加愿意使用 search() 函数,而不是 match() 函数**,使用match()函数会出现匹配失败的情况的。 |r'(?<=-)\w+' |abc-def | xyzdef |
|(?<!…) | 匹配当前位置之前不是 ... 的样式。这个叫 negative lookbehind assertion (后视断定取非)。|r'(?<!-)\w+' | xyzdef | abc-def|
## 正则函数使用
| 函数定义 | 含义 |
| :------ | :------------- |
|re.search(pattern, string, flags=0) | 扫描整个 字符串 找到匹配样式的第一个位置,并返回一个相应的 匹配对象。如果没有匹配,就返回一个 None ; 注意这和找到一个零长度匹配是不同的。|
|re.match(pattern, string, flags=0)|如果 string 开始的0或者多个字符匹配到了正则表达式样式,就返回一个相应的 匹配对象 。 如果没有匹配,就返回 None ;注意它跟零长度匹配是不同的。注意即便是 MULTILINE 多行模式, re.match() 也只匹配字符串的开始位置,而不匹配每行开始。如果你想定位 string 的任何位置,使用 search() 来替代。|
|re.fullmatch(pattern, string, flags=0)|如果整个 string 匹配到正则表达式样式,就返回一个相应的 匹配对象 。 否则就返回一个 None ;注意这跟零长度匹配是不同的。|
|re.split(pattern, string, maxsplit=0, flags=0)|用 pattern 分开 string 。 如果在 pattern 中捕获到括号,那么所有的组里的文字也会包含在列表里。如果 maxsplit 非零, 最多进行 maxsplit 次分隔, 剩下的字符全部返回到列表的最后一个元素。|
|re.findall(pattern, string, flags=0)|对 string 返回一个不重复的 pattern 的匹配列表, string 从左到右进行扫描,匹配按找到的顺序返回。如果样式里存在一到多个组,就返回一个组合列表;就是一个元组的列表(如果样式里有超过一个组合的话)。空匹配也会包含在结果里。|
|re.finditer(pattern, string, flags=0)|pattern 在 string 里所有的非重复匹配,返回为一个迭代器 iterator 保存了 匹配对象 。 string 从左到右扫描,匹配按顺序排列。空匹配也包含在结果里。|
|re.sub(pattern, repl, string, count=0, flags=0) | 返回通过使用 repl 替换在 string 最左边非重叠出现的 pattern 而获得的字符串。 如果样式没有找到,则不加改变地返回 string。 repl 可以是字符串或函数;如为字符串,则其中任何反斜杠转义序列都会被处理。|
|re.subn(pattern, repl, string, count=0, flags=0) | 行为与 sub() 相同,但是返回一个元组 (字符串, 替换次数).|
|re.escape(pattern) |转义 pattern 中的特殊字符。如果你想对任意可能包含正则表达式元字符的文本字符串进行匹配,它就是有用的。 |
|re.purge() | 清除正则表达式的缓存。|
### match() 与 search() 函数比较
Python 提供了两种不同的操作:基于 re.match() 检查字符串开头,或者 re.search() 检查字符串的任意位置(默认Perl中的行为)。
例如:
```Python
>>>
>>> re.match("c", "abcdef") # No match
>>> re.search("c", "abcdef") # Match
<re.Match object; span=(2, 3), match='c'>
```
在 search() 中,可以用 '^' 作为开始来限制匹配到字符串的首位:
```Python
>>>
>>> re.match("c", "abcdef") # No match
>>> re.search("^c", "abcdef") # No match
>>> re.search("^a", "abcdef") # Match
<re.Match object; span=(0, 1), match='a'>
```
**注意** `MULTILINE` 多行模式中函数 match() 只匹配字符串的开始,但使用 search() 和以 '^' 开始的正则表达式会匹配每行的开始
```Python
>>>
>>> re.match('X', 'A\nB\nX', re.MULTILINE) # No match
>>> re.search('^X', 'A\nB\nX', re.MULTILINE) # Match
<re.Match object; span=(4, 5), match='X'>
```
## 匹配对象处理函数
| 函数定义 | 含义 |
| :-------- | :------------- |
| Match.expand(template) | 对 template 进行反斜杠转义替换并且返回,就像 sub() 方法中一样。转义如同 \n 被转换成合适的字符,数字引用(\1, \2)和命名组合(\g<1>, \g<name>) 替换为相应组合的内容。|
|Match.group([group1, ...])|返回一个或者多个匹配的子组。如果只有一个参数,结果就是一个字符串,如果有多个参数,结果就是一个元组(每个参数对应一个项),如果没有参数,组1默认到0(整个匹配都被返回)。|
|Match.groups(default=None)|返回一个元组,包含所有匹配的子组,在样式中出现的从1到任意多的组合。 default 参数用于不参与匹配的情况,默认为 None。|
```Python
>>> m = re.match(r"(\w+) (\w+)", "Isaac Newton, physicist")
>>> m.group(0) # The entire match
'Isaac Newton'
>>> m.group(1) # The first parenthesized subgroup.
'Isaac'
>>> m.group(2) # The second parenthesized subgroup.
'Newton'
>>> m.group(1, 2) # Multiple arguments give us a tuple.
('Isaac', 'Newton')
>>> m = re.match(r"(\d+)\.?(\d+)?", "24")
>>> m.groups() # Second group defaults to None.
('24', None)
>>> m.groups('0') # Now, the second group defaults to '0'.
('24', '0')
```
- 课程大纲
- 入门篇
- 爬虫是什么
- 为什么要学习爬虫
- 爬虫的基本原理
- TCP/IP协议族的基本知识
- HTTP协议基础知识
- HTML基础知识
- HTML_DOM基础知识
- urllib3库的基本使用
- requests库的基本使用
- Web页面数据解析处理方法
- re库正则表达式的基础使用
- CSS选择器参考手册
- XPath快速了解
- 实战练习:百度贴吧热议榜
- 进阶篇
- 服务端渲染(CSR)页面抓取方法
- 客户端渲染(CSR)页面抓取方法
- Selenium库的基本使用
- Selenium库的高级使用
- Selenium调用JavaScript方法
- Selenium库的远程WebDriver
- APP移动端数据抓取基础知识
- HTTP协议代理抓包分析方法
- Appium测试Android应用基础环境准备
- Appium爬虫编写实战学习
- Appium的元素相关的方法
- Appium的Device相关操作方法
- Appium的交互操作方法
- 代理池的使用与搭建
- Cookies池的搭建与用法
- 数据持久化-数据库的基础操作方法(mysql/redis/mongodb)
- 执行JS之execjs库使用
- 高级篇
- Scrapy的基本知识
- Scrapy的Spider详细介绍
- Scrapy的Selector选择器使用方法
- Scrapy的Item使用方法
- Scrapy的ItemPipeline使用方法
- Scrapy的Shell调试方法
- Scrapy的Proxy设置方法
- Scrapy的Referer填充策略
- Scrapy的服务端部署方法
- Scrapy的分布式爬虫部署方法
- Headless浏览器-pyppeteer基础知识
- Headless浏览器-pyppeteer常用的设置方法
- Headless浏览器-反爬应对办法
- 爬虫设置技巧-UserAgent设置
- 反爬策略之验证码处理方法
- 反爬识别码之点击文字图片的自动识别方法
- 反爬字体处理方法总结
- 防止反爬虫的设置技巧总结
- 实战篇
- AJAX接口-CSDN技术博客文章标题爬取
- AJAX接口-拉购网职位搜索爬虫
- 执行JS示例方法一之动漫图片地址获取方法
- JS执行方法示例二完整mangabz漫画爬虫示例
- 应用实践-SOCKS代理池爬虫
- 落霞小说爬虫自动制作epub电子书
- 一种简单的适用于分布式模式知乎用户信息爬虫实现示例
- 法律安全说明