简单应用"/>
正则表达式介绍+一些简单应用
一、正则语句介绍
语法 | 说明 | 表达式示例 | 完整匹配的字符串 |
一般字符 | 匹配自身 | abc | abc |
. | 除换行符'\n'以外的任意字符 | a.c | abc |
\ | 转义字符,是后一个字符改变原来的意思 | a\.c | a.c |
[...] | 字符集,所有的特殊字符在字符集中都失去其原有的特殊含义 | a[bcd]e | abe ace ade |
\d | 数字[0-9] | a\dc | a1c |
\D | 非数字[^\d] | a\Dc | abc |
\s | 空白符 [<空格>\t\r\n\f\v] | a\sc | a c |
\S | 非空白字符[^\s] | a\Sc | abc |
\w | 单词字符[A-Za-z0-9_] | a\wc | abc |
\W | 非单词字符 [^\W] | a\Wc | a c |
* | 匹配前一个字符0或无限次 | abc* | ab abcccccc |
+ | 匹配前一个字符1次或无限次 | abc+ | abc abccccc |
? | 匹配前一个字符0或1次 | abc? | ab abc |
{m} | 匹配前一个字符m次 | ab{2}c | abbc |
{m,n} | 匹配前一个字符m到n次 | ab{1,2}c | abc abbc |
^ | 开头 | ^abc | abc |
$ | 末尾 | abc$ | abc |
\A | 仅匹配字符串开头 | ||
\Z | 仅匹配字符串末尾 | ||
\b | 匹配单词和非单词之间 | a\b!bc | a!bc |
\B | [^\b] | a\Bbc | abc |
| | 左右表达式任意匹配一个(先尝试左边) | abc|def | abc def |
(...) | 分组表达式 | (abc){2} | abcabc |
(?P=name) | 分组,除了原有的编号外在指定一个额外的别名 | ||
\<number> | 引用编号为<number>的分组匹配到的字符串 | ||
(?P=name) | 引用别名为<name>的分组匹配到的字符串 |
1、贪婪模式
正则表达式通常用于在文本中查找匹配的字符串。Python里数量词默认是贪婪的,总是尝试匹配尽可能多的字符;非贪婪的则相反,总是尝试匹配尽可能少的字符。例如:正则表达式"ab"如果用于查找"abbbc",将找到"abbb"。而如果使用非贪婪的数量词"ab?",将找到"a"。
2. 反斜杠的困扰
正则表达式里使用"\"作为转义字符,这就可能造成反斜杠困扰。假如你需要匹配文本中的字符"\",那么使用编程语言表示的正则表达式里将需要4个反斜杠"\\\\":前两个和后两个分别用于在编程语言里转义成反斜杠,转换成两个反斜杠后再在正则表达式里转义成一个反斜杠。
3. 匹配模式
正则表达式提供了一些可用的匹配模式,比如忽略大小写、多行匹配等
二、re模块简介
聊到Python正则表达式的支持,首先肯定会想到re
库,这是一个Python处理文本的标准库。
标准库的意思表示这是一个Python内置模块,不需要额外下载,目前Python内置模块大概有300个。可以在这里查看Python所有的内置模块:Python Module Index — Python 3.10.3 documentation
因为re是内置模块,所以不需要再下载,使用时直接引入即可: import re
re模块官方文档:re --- 正则表达式操作 — Python 3.8.13 文档
re模块库源码:.8/Lib/re.p
三、re模块常量
常量即表示不可更改的变量,一般用于做标记。
re模块中有9个常量,常量的值都是int类型!
1. IGNORECASE
语法: re.IGNORECASE 或简写为 re.I
作用: 进行忽略大小写匹配。
代码案例:
text = '这是一个例子b'
pattern = r'这是一个例子B'
print('默认模式', re.findall(pattern, text))
print('忽略大小写', re.findall(pattern, text, re.I))默认模式:[]
忽略大小写:['这是一个例子B']
在默认匹配模式下大写字母B无法匹配小写字母b,而在 忽略大小写 模式下是可以的。
2. ASCII
语法: re.ASCII 或简写为 re.A
作用: 顾名思义,ASCII表示ASCII码的意思,让 \w
, \W
, \b
, \B
, \d
, \D
, \s
和 \S
只匹配ASCII,而不是Unicode。
代码案例:
text = '这是a一个例子b'
pattern = r'\w+'
print('Unicode', re.findall(pattern, text))
print('ASCII', re.findall(pattern, text, re.A))Unicode:['这是a一个例子b']
ASCII:['a','b']
在默认匹配模式下\w+
匹配到了所有字符串,而在ASCII模式下,只匹配到了a、b、c(ASCII编码支持的字符)。
注意:这只对字符串匹配模式有效,对字节匹配模式无效。
3. DOTALL
语法: re.DOTALL 或简写为 re.S
作用: DOT表示.
,ALL表示所有,连起来就是.
匹配所有,包括换行符\n
。默认模式下.
是不能匹配行符\n
的。
代码案例:
text = '这是一个\n例子'
pattern = r'.*'
print('默认模式', re.findall(pattern, text))
print('匹配所有模式', re.findall(pattern, text, re.S))默认模式:['这是一个', '', '例子', '']
匹配所有模式:['这是一个\n例子', '']
在默认匹配模式下.
并没有匹配换行符\n
,而是将字符串分开匹配;而在re.DOTALL模式下,换行符\n
与字符串一起被匹配到。
注意:默认匹配模式下.
并不会匹配换行符\n
。
4. MULTILINE
语法: re.MULTILINE 或简写为 re.M
作用: 多行模式,当某字符串中有换行符\n
,默认模式下是不支持换行符特性的,比如:行开头 和 行结尾,而多行模式下是支持匹配行开头的。
代码案例:
text = '这是\n一个例子'
pattern = r'^一个例子'
print('默认模式', re.findall(pattern, text))
print('多行', re.findall(pattern, text, re.M))默认模式:[]
多行:['一个例子']
正则表达式中^
表示匹配行的开头,默认模式下它只能匹配字符串的开头;而在多行模式下,它还可以匹配 换行符\n
后面的字符。
注意:正则语法中^
匹配行开头、\A
匹配字符串开头,单行模式下它两效果一致,多行模式下\A
不能识别\n
。
四、re模块函数
re模块有12个函数,重点介绍常用模块。
1.查找一个匹配项
查找并返回一个匹配项的函数有3个:search、match、fullmatch,他们的区别分别是:
-
search: 查找任意位置的匹配项
-
match: 必须从字符串开头匹配
-
fullmatch: 整个字符串与正则完全匹配
我们再来根据实际的代码案例比较:
案例1:
import re
text = 'a这是一个例子b,这是一个例子b'
pattern = r'这是一个例子b'print('search:', re.search(pattern, text).group())
print('match:', re.match(pattern, text))
print('fullmatch: ', re.fullmatch(pattern,text))search:这是一个例子b
match:None
fullmatch:None
案例1中search函数是在字符串中任意位置匹配,只要有符合正则表达式的字符串就匹配成功,其实有两个匹配项,但search函数值返回一个。
而match函数是要从头开始匹配,而字符串开头多了个字母a
,所以无法匹配,fullmatch函数需要完全相同,故也不匹配!
2.查找多个匹配项
讲完查找一项,现在来看看查找多项吧,查找多项函数主要有:findall函数 与 finditer函数:
-
findall: 从字符串任意位置查找,返回一个列表
-
finditer:从字符串任意位置查找,返回一个迭代器
两个方法基本类似,只不过一个是返回列表,一个是返回迭代器。我们知道列表是一次性生成在内存中,而迭代器是需要使用时一点一点生成出来的,内存使用更优。
import re
text = 'a这是一个例子b,这是一个例子b'
pattern = r'这是一个例子b'
print('findall:', re.findall(pattern, text))
print('finditer:', list(re.finditer(pattern, text)))findall: ['这是一个例子b', '这是一个例子b']
finditer: [<_sre.SRE_Match object; span=(1, 8), match='这是一个例子b'>, <_sre.SRE_Match object; span=(9, 16), match='这是一个例子b'>]
如果可能存在大量的匹配项的话,建议使用finditer函数,一般情况使用findall函数基本没啥影响。
3.分割
re.split(pattern, string, maxsplit=0, flags=0) 函数:用 pattern 分开 string , maxsplit表示最多进行分割次数, flags表示模式,就是上面我们讲解的常量!
import re
text = 'a这是一个例子b,这是一个例子b'
pattern = r','
print('split: ', re.split(pattern,text,maxsplit=1,flags=re.I))split: ['a这是一个例子b', '这是一个例子b']
注意:str
模块也有一个 split函数 ,那这两个函数该怎么选呢? str.split函数功能简单,不支持正则分割,而re.split支持正则。
关于二者的速度如何? 在 不需要正则支持 且 数据量和数次不多 的情况下使用str.split
函数更合适,反之则使用re.split
函数。
4.替换
替换主要有sub函数 与 subn函数,他们功能类似!
先来看看sub函数的用法:
re.sub(pattern, repl, string, count=0, flags=0) 函数参数讲解:repl替换掉string中被pattern匹配的字符, count表示最大替换次数,flags表示正则表达式的常量。
值得注意的是:sub函数中的入参:repl替换内容既可以是字符串,也可以是一个函数哦! 如果repl为函数时,只能有一个入参:Match匹配对象。
re.subn(pattern, repl, string, count=0, flags=0) 函数与 re.sub函数 功能一致,只不过返回一个元组 (字符串, 替换次数)。
5.编译正则对象
compile函数 与 template函数 将正则表达式的样式编译为一个 正则表达式对象 (正则对象Pattern),这个对象与re模块有同样的正则函数(后面我们会讲解Pattern正则对象)。
import re
text = 'a这是一个例子b,这是一个例子b'
pattern = r'这是一个例子b'
pattern_obj = re.compile(pattern)
# 查找任意位置
print('search:', pattern_obj.search(text).group())search: 这是一个例子b
而template函数 与 compile函数 类似,只不过是增加了我们之前说的re.TEMPLATE 模式
五、正则对象Pattern
1. 与re模块 函数一致
.在re
模块的函数中有一个重要的函数 compile函数 ,这个函数可以预编译返回一个正则对象,此正则对象拥有与re
模块相同的函数.
既然是一致的,那到底该用re模块 还是 正则对象Pattern ?
而且,有些同学可能看过re
模块的源码,你会发现其实compile函数 与 其他 re函数(search、split、sub等等) 内部调用的是同一个函数,最终还是调用正则对象的函数!
就是以下两种代码的底层实现是一致的:
# re函数
re.search(pattern, text)
# 正则对象函数
compile = re.compile(pattern)
compile.search(text)
官方文档推荐:在多次使用某个正则表达式时推荐使用正则对象Pattern 以增加复用性,因为通过 re.compile(pattern) 编译后的模块级函数会被缓存!
六、注意事项
1.字节串 与 字符串
模式和被搜索的字符串既可以是Unicode字符串(str),也可以是8位字节串(bytes)。但是,两者不能混用!
2.r 的作用
正则表达式使用反斜杠('')来表示特殊形式,或者把特殊字符转义成普通字符。
而反斜杠在普通的 Python 字符串里也有相同的作用,所以就产生了冲突。
解决办法是对于正则表达式样式使用 Python 的原始字符串表示法;在带有 'r' 前缀的字符串字面值中,反斜杠不必做任何特殊处理。
3.正则查找函数 返回匹配对象
查找一个匹配项(search、match、fullmatch)的函数返回值都是一个匹配对象Match,需要通过match.group()获取匹配值。
match.group()和match.groups()也是有区别的。
4.重复使用某个正则
如果要重复使用某个正则表达式,推荐使用re.compile(pattern)函数返回一个正则对象。
七、re.compile、re.match及re.search函数用法详解
参考 .htm
1、re.compile() 函数
编译正则表达式模式,返回一个对象。可以把常用的正则表达式编译成正则表达式对象,方便后续调用及提高效率。
re.compile(pattern, flags=0)
- pattern 指定编译时的表达式字符串
- flags 编译标志位,用来修改正则表达式的匹配方式。支持 re.L|re.M 同时匹配
flags 标志位参数
re.I(re.IGNORECASE)
使匹配对大小写不敏感
re.L(re.LOCAL)
做本地化识别(locale-aware)匹配
re.M(re.MULTILINE)
多行匹配,影响 ^ 和 $
re.S(re.DOTALL)
使 . 匹配包括换行在内的所有字符
re.U(re.UNICODE)
根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B.
re.X(re.VERBOSE)
该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。
示例:
1 2 3 4 5 6 7 |
|
findall 返回的是一个 list 对象
<class '_sre.SRE_Pattern'>
<class 'list'>
['wang', 'WANG']
2、re.match() 函数
总是从字符串‘开头曲匹配',并返回匹配的字符串的 match 对象 <class '_sre.SRE_Match'>。
re.match(pattern, string[, flags=0])
- pattern 匹配模式,由 re.compile 获得
- string 需要匹配的字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
hello
b 失败
c 失败
hello
match 的方法和属性
参考链接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
返回结果:
group 0: hello world!
group 1: hello
group 2:
group 3: world!
groups: ('hello', ' ', 'world!')
start 0: 0 end 0: 12
start 1: 0 end 1: 5
start 2: 0 end 2: 6
pos 开始于: 0
endpos 结束于: 25
lastgroup 最后一个被捕获的分组的名字: last
lastindex 最后一个分组在文本中的索引: 3
string 匹配时候使用的文本: hello world! hello python
re 匹配时候使用的 Pattern 对象: re.compile('(?P<first>hell\\w)(?P<symbol>\\s)(?P<last>.*ld!)')
span 返回分组匹配的 index (start(group),end(group)): (5, 6)
3、re.search 函数
对整个字符串进行搜索匹配,返回第一个匹配的字符串的 match 对象。
re.search(pattern, string[, flags=0])
- pattern 匹配模式,由 re.compile 获得
- string 需要匹配的字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
注意 re.search 和 re.match 匹配的 str 的区别
打印结果:
group 0: hello world!
group 1: hello
group 2:
group 3: world!
groups: ('hello', ' ', 'world!')
start 0: 4 end 0: 16
start 1: 4 end 1: 9
start 2: 4 end 2: 10
pos 开始于: 0
endpos 结束于: 29
lastgroup 最后一个被捕获的分组的名字: last
lastindex 最后一个分组在文本中的索引: 3
string 匹配时候使用的文本: say hello world! hello python
re 匹配时候使用的 Pattern 对象: re.compile('(?P<first>hell\\w)(?P<symbol>\\s)(?P<last>.*ld!)')
span 返回分组匹配的 index (start(group),end(group)): (9, 10)
八、一些简单应用
1、识别网页文本信息中的公网安 备案号
示例:沪公网备标识31011202007523
闽公网安备35020302000108号
京公网安备11010502026042
分析:【前边一个字是每个省的简称】+【公网安备,还可能有 标识】+【数字特征】+【可能有 号】
import re
pattern = re.compile("[京津晋冀蒙辽吉黑沪苏浙皖闽赣鲁豫鄂湘粤桂琼渝川贵云藏陕甘青宁新]公网安['标识','备','证']\s*\d{10,15}号?")
number = pattern.findall(col)
2、匹配某两个字符之间的信息
示例:提取gene_name信息:
Gene_id=XLOC_003495;Gene_name=linc-DTHD1-11;Tr... |
reee = re.search(r'[g|G]ene_name.+?;', xxx, flags=0, )
reee.group()[:-1] if reee else None
3、匹配电话号码
import re
phone = "2004-959-559 # 这是一个电话号码"
# 删除注释
num = re.sub(r'#.*$', "", phone)
print ("电话号码 : ", num) # 电话号码 : 2004-959-559 # 移除非数字的内容
num = re.sub(r'\D', "", phone)
print ("电话号码 : ", num)
参考文献:
更多推荐
正则表达式介绍+一些简单应用
发布评论