06 Python爬虫之Re(正则表达式)库
正则表达式是用来简洁表达一组字符串的表达式
一、正则表达式的语法
1.1 正则表达式的常用操作符
操作符 | 说明 | 实例 |
---|---|---|
. | 表示任何单个字符 | |
[ ] | 字符集,对单个字符给出取值范围 | [abc]表示a、b、c,[a‐z]表示a到z单个字符 |
[^ ] | 非字符集,对单个字符给出排除范围 | [^abc]表示非a或b或c的单个字符 |
* | 前一个字符0次或无限次扩展 | abc* 表示ab、abc、abcc、abccc等 |
+ | 前一个字符1次或无限次扩展 | abc+ 表示abc、abcc、abccc等 |
? | 前一个字符0次或1次扩展 | abc? 表示ab、abc |
| | 左右表达式任意一个abc | def表示abc、def |
扩展前一个字符m次 | ab{2}c表示abbc | |
扩展前一个字符m至n次(含n) | ab{1,2}c表示abc、abbc | |
^ | 匹配字符串开头 | ^abc表示abc且在一个字符串的开头 |
$ | 匹配字符串结尾 | abc$表示abc且在一个字符串的结尾 | ||
( ) | 分组标记,内部只能使用操作符 | (abc)表示abc,(abc|def)表示abc、def |
\d | 数字,等价于[0‐9] | |
\D | 非数字 | |
\w | 单词字符(数字/字母/下划线),等价于[A‐Za‐z0‐9_] | |
\W | 非数字/非字母/非下划线 | |
\s | 空格/ \t / \n | |
\S | 非空格/ 非\t / 非\n |
实例:
. 任意字符(换行符除外)
表示任意单个字符
import re
s= 'abc12ab56bc'
# .: 任意字符(换行符除外)
print(re.findall(".",s))
['a', 'd', 'a', 's', 'd', 'a', 's', 'd', 'a', 's', 'd', 'a', 's', 'f', 'a', 's', 'f', '\t']
[] 元字符(字符集)
匹配中间的字符,只要单个字符
也可以使用[a-z]表示a到z 单个字符
import re
s = "adasdasdasdasfasf\n\t"
# []: 匹配中间的字符,只要单个字符
print(re.findall("[acef]",s))
['a', 'a', 'a', 'a', 'a', 'f', 'a', 'f']
[^] 反取
^对[]内的元素取反,除了[]里的字符都要
import re
s = "adasdasdasdasfasf\n\t"
# [^] : 把[]中的字符给排除.
print(re.findall("[^acef]",s))
['d', 's', 'd', 's', 'd', 's', 'd', 's', 's', '\n', '\t']
* 对前一个字符0-无穷次扩展
*: 匹配 *前面的字符0-无穷个,空也会匹配
import re
s = r"abaacaaaaa"
# *: 匹配 *前面的字符0-无穷个
print(re.findall("a*",s)) # 匹配 0-无限个a,空也会匹配
['a', '', 'aa', '', 'aaaaa', '']
+ 对前一个字符1-无穷次扩展
+: 匹配 +前面的字符1-无穷个
import re
s = r"abaacaaaaa"
# +: 匹配 +前面的字符1-无穷个
print(re.findall("a+",s)) # 匹配 1-无限个a
['a', 'aa', 'aaaaa']
? 对前一个字符0或1次扩展
?: 匹配 ?前面的字符0或1次扩展
import re
s = r"abaacaaaaa"
# ?: 匹配 ?前面的字符0-1个
print(re.findall("a?",s)) # 匹配 0-1个a
['a', '', 'a', 'a', '', 'a', 'a', 'a', 'a', 'a', '']
| 左右两边的字符都要
A|B: A和B都要
import re
s = 'abacad'
# A|B: A和B都要
print(re.findall('a|b', s))
['a', 'b', 'a', 'a']
{m} 对前一个字符扩展m次
{m}: 匹配 {m}前面的字符m次
import re
s = r"abaacaaaaa"
# {m}: 匹配 前面的字符m个
print(re.findall("a{2}",s)) # 匹配 2个a
['aa', 'aa', 'aa']
{m,n} 对前一个字符扩展m-n次(含n)
{m,n}: 匹配 前面的的字符m-n个
import re
s = r"abaacaaaaa"
# {m,n}: 匹配 前面的的字符m-n个
print(re.findall("a{2,3}",s)) # 匹配 2、3个a
['aa', 'aaa', 'aa']
^ 元字符
字符串开始位置与匹配规则符合就匹配,否则不匹配
匹配字符串开头。在多行模式中匹配每一行的开头(Python3+已经失效,配合compile使用)
import re
s = '王大炮打炮被大炮打死了 王大炮打炮被大炮打死了'
# ^: 匹配开头
print(re.findall("^王大炮", s))
['王大炮']
$ 元字符
字符串结束位置与匹配规则符合就匹配,否则不匹配
匹配字符串末尾,在多行模式中匹配每一行的末尾
import re
s = '王大炮打炮被大炮打死了 王大炮打炮被大炮打死了'
# $: 匹配结尾
print(re.findall("打死了$", s))
['打死了']
() 只要括号内的
(): 只要括号内的
import re
s = 'abacad'
# (): 只要括号内的
print(re.findall('a(.)', s))
['b', 'c', 'd']
\d 匹配单个数字(0-9)
\d: 匹配单个数字
import re
s = '1#@¥23abc123 \n_def\t456'
# \d: 匹配单个数字
print(re.findall("\d",s)) # 匹配 单个数字
['1', '2', '3', '1', '2', '3', '4', '5', '6']
\D 匹配单个非数字(包括\n)
\D: 匹配单个非数字
import re
s = '1#@¥23abc123 \n_def\t456'
# \D: 匹配单个非数字
print(re.findall("\D",s)) # 匹配 单个 非数字(包括\n)
['#', '@', '¥', 'a', 'b', 'c', ' ', '\n', '_', 'd', 'e', 'f', '\t']
\w 匹配 数字/字母/下划线
\w: 匹配 数字/字母/下划线
import re
s = '1#@¥23abc123 \n_def\t456'
# \w: 匹配 数字/字母/下划线
print(re.findall("\w",s))
['1', '2', '3', 'a', 'b', 'c', '1', '2', '3', '_', 'd', 'e', 'f', '4', '5', '6']
\W 匹配 非数字/非字母/非下划线
\W: 非数字/非字母/非下划线
import re
s = '1#@¥23abc123 \n_def\t456'
# \W: 非数字/非字母/非下划线
print(re.findall("\W",s))
['#', '@', '¥', ' ', '\n', '\t']
\s 匹配 空格/ \t/ \n
\s: 空格/ \t/ \n
import re
s = '1#@¥23abc123 \n_def\t456'
# \s: 空格/ \t/ \n
print(re.findall("\s", s))
[' ', '\n', '\t']
\S 匹配 非空格/ 非\t/ 非\m
\S: 非空格/ 非\t/ 非\m
import re
s = '1#@¥23abc123 \n_def\t456'
# \S: 非空格/ 非\t/ 非\m
print(re.findall("\S", s))
['1', '#', '@', '¥', '2', '3', 'a', 'b', 'c', '1', '2', '3', '_', 'd', 'e', 'f', '4', '5', '6']
二、Re库的基本使用
2.1 Re库介绍
Re库是Python的标准库,主要用于字符串匹配
**调用方式:import re**
2.2 Re库主要功能函数
函数 | 说明 |
---|---|
re.search() | 在一个字符串中搜索匹配正则表达式的第一个位置,返回match对象 |
re.match() | 从一个字符串的开始位置起匹配正则表达式,返回match对象 |
re.findall() | 搜索字符串,以列表类型返回全部能匹配的子串 |
re.split() | 将一个字符串按照正则表达式匹配结果进行分割,返回列表类型 |
re.finditer() | 搜索字符串,返回一个匹配结果的迭代类型,每个迭代元素是match对象 |
re.sub() | 在一个字符串中替换所有匹配正则表达式的子串,返回替换后的字符串 |
re.search(pattern,string,flags=0)
在一个字符串中搜索匹配正则表达式的第一个位置 返回match对象
- pattern : 正则表达式的字符串或原生字符串表示
- string : 待匹配字符串
- flags : 正则表达式使用时的控制标记
re.match(pattern,string,flags=0)
从一个字符串的开始位置起匹配正则表达式 返回match对象
- pattern : 正则表达式的字符串或原生字符串表示
- string : 待匹配字符串
- flags : 正则表达式使用时的控制标记
re.findall(pattern,string,flags=0)
搜索字符串,以列表类型返回全部能匹配的子串
- pattern : 正则表达式的字符串或原生字符串表示
- string : 待匹配字符串
- flags : 正则表达式使用时的控制标记
re.split(pattern,string,maxsplit=0,flags=0)
将一个字符串按照正则表达式匹配结果进行分割 返回列表类型
- pattern : 正则表达式的字符串或原生字符串表示
- string : 待匹配字符串
- maxsplit: 大分割数,剩余部分作为后一个元素输出
- flags : 正则表达式使用时的控制标记
re.finditer(pattern,string,flags=0)
搜索字符串,返回一个匹配结果的迭代类型,每个迭代元素是match对象
- pattern : 正则表达式的字符串或原生字符串表示
- string : 待匹配字符串
- flags : 正则表达式使用时的控制标记
re.sub(pattern,repl, string,count=0,flags=0)
在一个字符串中替换所有匹配正则表达式的子串 返回替换后的字符串
- pattern : 正则表达式的字符串或原生字符串表示
- repl: 替换匹配字符串的字符串
- string : 待匹配字符串
- count : 匹配的大替换次数
- flags : 正则表达式使用时的控制标记
2.3 Re库的另一种等价用法
regex = re.compile(pattern,flags=0)
将正则表达式的字符串形式编译成正则表达式对象
- pattern : 正则表达式的字符串或原生字符串表示
- flags : 正则表达式使用时的控制标记
函数 | 说明 |
---|---|
regex.search() | 在一个字符串中搜索匹配正则表达式的第一个位置,返回match对象 |
regex.match() | 从一个字符串的开始位置起匹配正则表达式,返回match对象 |
regex.findall() | 搜索字符串,以列表类型返回全部能匹配的子串 |
regex.split() | 将一个字符串按照正则表达式匹配结果进行分割,返回列表类型 |
regex.finditer() | 搜索字符串,返回一个匹配结果的迭代类型,每个迭代元素是match对象 |
regex.sub() | 在一个字符串中替换所有匹配正则表达式的子串,返回替换后的字符串 |
2.4 正则表达式使用时的控制标记 flags
修饰符 | 描述 |
---|---|
re.I | 使匹配对大小写不敏感,忽略正则表达式的大小写,[A‐Z]能够匹配小写字符 |
re.L | 做本地化识别(locale-aware)匹配 |
re.M | 正则表达式中的^操作符能够将给定字符串的每行当作匹配开始 |
re.S | 正则表达式中的.操作符能够匹配所有字符,默认匹配除换行外的所有字符 |
re.U | 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B. |
re.X | 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。 |
三、Re库的Match对象
Match对象是一次匹配的结果,包含匹配的很多信息
3.1 Match对象的属性
属性 | 说明 |
---|---|
.string | 待匹配的文本 |
.re | 匹配时使用的patter对象(正则表达式) |
.pos | 正则表达式搜索文本的开始位置 |
.endpos | 正则表达式搜索文本的结束位置 |
3.2 Match对象的方法
属性 | 说明 |
---|---|
.group(0) | 获得匹配后的字符串 |
.start() | 匹配字符串在原始字符串的开始位置 |
.end() | 匹配字符串在原始字符串的结束位置 |
.span() | 返回(.start(), .end()) |
四、Re库的贪婪匹配和最小匹配
Re库默认采用贪婪匹配,即输出匹配长的子串
4.1 最小匹配
操作符 | 说明 |
---|---|
*? | 前一个字符0次或无限次扩展,小匹配 |
+? | 前一个字符1次或无限次扩展,小匹配 |
?? | 前一个字符0次或1次扩展,小匹配 |
{m,n}? | 扩展前一个字符m至n次(含n),小匹配 |
只要长度输出可能不同的,都可以通过在操作符后增加?变成小匹配
*. 贪婪模式
.*: 贪婪模式(最大化),找到继续找,让结果最大化
import re
s = 'abbbcabc'
# .*: 贪婪模式(最大化),找到继续找,让结果最大化
print(re.findall('a.*c', s))
print(re.findall('a.+c', s))
['abbbcabc']
['abbbcabc']
.*? 非贪婪模式(最小匹配)
.*?: 非贪婪模式(最小化),找到就马上停止
import re
s = 'abbbcabc'
# .*?: 非贪婪模式(最小化),找到就马上停止
print(re.findall('a.*?c', s))
print(re.findall('a.+?c', s))
['abbbc', 'abc']
['abbbc', 'abc']