Python之路(第二十一篇) re模块
一、re模块
正则表达式本身是一种小型的、高度专业化的编程语言,正则表达式就是字符串的匹配规则,在多数编程语言里都有相应的支持,python里对应的模块是re,正则表达式模式被编译成一系列的字节码,然后由用 C 编写的匹配引擎执行。
匹配语法
re方法(匹配模式,字符串,flag)
(一)字符
1、元字符
普通字符 | 匹配内容 |
---|---|
. | 匹配任意除换行符"\n"外的字符,若指定flag DOTALL,则匹配任意字符,包括换行 |
\ | 转义字符,使后一个字符改变原来的意思 |
* | 匹配前一个字符0或多次 |
+ | 匹配前一个字符1次或无限次 |
? | 匹配一个字符0次或1次, 和防止贪婪匹配 |
^ | 匹配字符串开头。在多行模式中匹配每一行的开头,^元字符如果写到[]字符集里就是反取 |
$ | 匹配字符串末尾,在多行模式中匹配每一行的末尾 |
| | 或。匹配|左右表达式任意一个,从左到右匹配,如果|没有包括在()中,则它的范围是整个正则表达式 |
{} | {m}匹配前一个字符m次,{m,n}匹配前一个字符m至n次,若省略n,则匹配m至无限次 |
[] | 字符集。对应的位置可以是字符集中任意字符。字符集中的字符可以逐个列出,也可以给出范围,如[abc]或[a-c]。abc表示取反,即非abc。所有特殊字符在字符集中都失去其原有的特殊含义。用\反斜杠转义恢复特殊字符的特殊含义。 |
() | 被括起来的表达式将作为分组,从表达式左边开始没遇到一个分组的左括号“(”,编号+1.分组表达式作为一个整体,可以后接数量词。表达式中的|仅在该组中有效。 匹配任何在圆括号内的正则表达式, 并表明分组的开始和结束; 分组的内容在完成匹配后可以提取出来,而且可以在后面的字符串中用特殊的number 序列匹配 |
量词
量词 |
用法说明 |
---|---|
* | 重复零次或更多次 |
+ | 重复一次或更多次 |
? | 重复零次或一次 |
{n} | 重复n次 |
{n,} | 重复n次或更多次 |
{n,m} | 重复n到m次 |
元字符匹配次数说明
例子
import re
# '.'字符 , 从开头一直找 ,返回找到的所有字符
print(re.findall("nichol..","nicknicholas")) #['nicholas']
#'^'匹配字符串开头。在多行模式中匹配每一行的开头
print(re.findall("^nick","nickcalnicholas")) #['nick']
#'$'匹配字符串末尾,在多行模式中匹配每一行的末尾
print(re.findall("ick$","nicholasnicknick")) #['ick']
# '*' 匹配*号前的字符0次或多次
print(re.findall("a*","abcabaad")) #['a', '', '', 'a', '', 'aa', '', '']
# '+' 匹配前一个字符1次或多次
print(re.findall("a+","abcabaad")) #['a', 'a', 'aa']
# '?' 匹配前一个字符1次或0次
print(re.findall("a?","abcabaad")) #['a', '', '', 'a', '', 'a', 'a', '', '']
# '|' 或。匹配|左右表达式任意一个,从左到右匹配,如果|没有包括在()中,则它的范围是整个正则表达式
print(re.findall("(ab|AC)","abcadxyzab")) #['ab', 'ab']
print(re.findall("(ab|AC)","ACxyznick")) #['AC']
# '{m}'匹配前一个字符m次,{m,n}匹配前一个字符m至n次,若省略n,则匹配m至无限次
print(re.findall("a{2,4}","abcaadaxyzaaaa")) #['aa', 'aaaa']
# '[]'字符集。对应的位置可以是字符集中任意字符。字符集中的字符可以逐个列出,也可以给出范围,如[abc]或[a-c]。
print(re.findall("[ac]","acxyzabc")) #['a', 'c', 'a', 'c']
print(re.findall("[^ac]","acxyzabc")) #['x', 'y', 'z', 'b']
print(re.findall('a[bc]d','acd')) #['acd']
print(re.findall('[a-z]','acd')) #['a', 'c', 'd']
print(re.findall('[1-9]','45dha3')) #['4', '5', '3']
print(re.findall('[^ab]','45bdha3')) #['4', '5', 'd', 'h', '3']
print(re.findall('[\d]','45bdha3')) #['4', '5', '3']
# '()'匹配被括起来的内容
print(re.findall("(ab)",'xyz453d6gab89uzaxby')) #['ab']
print(re.findall("(ab)",'xyz453d6gab89uzaby')) #['ab', 'ab']
print(re.findall(r'(ad)+', 'addhahdwha2e3adadad')) #['ad', 'ad']
2、预定义字符集
预定义字符 | 匹配说明 |
---|---|
\d | 数字:[0-9] 字符英文说明digit |
\D | 等同于非数字:[^0-9] |
\s | 匹配任意的空白符:[<空格>\t\r\n\f\v] 可以匹配空格、换行符、缩进符号等 . 字符英文说明space |
\S | 非空白字符:[^\s] |
\w | 匹配包括下划线在内的任何字字符:[A-Za-z0-9_](大小写的A-Z,数字0-9) 字符英文说明word |
\W | 匹配非字母字符,即匹配特殊字符 |
\A | 仅匹配字符串开头,同^ |
\Z | 仅匹配字符串结尾,同$ |
\b | 匹配\w和\W之间,即匹配单词边界匹配一个单词边界,也就是指单词和空格间的位置。例如, 'lo\b' 可以匹配"hello" 中的 'lo',但不能匹配 "hellohi" 中的 'lo'。 |
\B | [^\b]匹配所有的非边界字符 |
例子
import re
# 匹配数字:[0-9]
print(re.findall("\d","你好我11大22,求十大3")) #['1', '1', '2', '2', '3']
#匹配非数字[0-9]
print(re.findall("\D","你好我11大22,求十大3")) #['你', '好', '我', '大', ',', '求', '十', '大']
# 匹配任意的空白符(打印不出来的)
print(re.findall("\s","你好我好\n,大家好\t")) #['\n', '\t']
# 匹配非空白字符:[^\s]
print(re.findall("\S","你好我好\n,大家好\t")) #['你', '好', '我', '好', ',', '大', '家', '好']
# 匹配包括下划线在内的任何字字符:[A-Za-z0-9_](大小写的A-Z,数字0-9),python中支持中文
print(re.findall("\w","ni好2_,大家好,HI\n")) #['n', 'i', '好', '2', '_', '大', '家', '好', 'H', 'I']
# 仅匹配字符串开头,同^
print(re.findall("\Ah","hell hello")) #['h']
# 仅匹配字符串结尾,同$
print(re.findall("o\Z","hellhello")) #['o']
# \b匹配\w和\W之间,即匹配单词边界匹配一个单词边界,也就是指单词和空格间的位置。
print(re.findall("\\b","hello word")) #['', '', '', ''] 把两个单词左右的空格边界匹配到了这里多加一个斜杠是为了转义
print(re.findall(r"\b","hello word")) #['', '', '', ''],或者不转义直接加r
3、字符集[]
字符集 | 说明 |
---|---|
[0-9] |
也可以用-表示范围,[0-9]就和[0123456789]是一个意思` |
[a-z] |
同样的如果要匹配所有的小写字母,直接用[a-z]就可以表示 |
[A-Z] |
[A-Z]就表示所有的大写字母 |
[0-9a-fA-F] |
可以匹配数字,大小写形式的a~f,用来验证十六进制字符 |
[A-z] |
可以匹配所有的大写字母和小写字母 |
例子
import re
print(re.findall("[0-9]+","add1ab21cc332ab")) #['1', '21', '332']
print(re.findall("[2-9]+","add1ab21cc332ab")) #['2', '332']
print(re.findall("[a-z]+","aadddccda")) #['aadddccda']
print(re.findall("[c-z]+","aadddcacda")) #['dddc', 'cd']
print(re.findall("[A-z]","A,BC,abc")) #['A', 'B', 'C', 'a', 'b', 'c']
4、()元字符,分组
也就是分组匹配,()里面的为一个组也可以理解成一个整体
如果()后面跟的是特殊元字符如 (adc)* , 那么*控制的前导字符就是()里的整体内容,不再是前导一个字符
例子
import re
print(re.findall("(ab)+","addabccab")) #['ab', 'ab']
5、r原生字符
将在python里有特殊意义的字符如\b,转换成原生字符(就是去除它在python的特殊意义),不然会给正则表达式有冲突,为了避免这种冲突可以在规则前加原始字符r,或者加上转义符\
例子
print(re.findall("\\b","hello word"))
print(re.findall(r"\b","hello word"))
r是real的意思
6、注意
(1) ^有两种用法,一种是作为开头,表示匹配字符串开头。第二种是非,在字符集里用表示非
如[^0-9]
表示匹配非数字0-9
(2)在正则表达式中,有很多有特殊意义的是元字符,比如\d和\s等,如果要在正则中匹配正常的"\d"而不是"数字"就需要对"\"进行转义,变成'\'。
在python中,无论是正则表达式,还是待匹配的内容,都是以字符串的形式出现的,在字符串中\也有特殊的含义,本身还需要转义。所以如果匹配一次"\d",字符串中要写成'\d',那么正则里就要写成"\\d",这样就太麻烦了。这个时候我们就用到了r'\d'这个概念,此时的正则是r'\d'就可以了。
(3)注意^和$使用所在的位置。匹配开头^要在被匹配的字符前面即“^a”,匹配结尾 $要在被匹配的字符后面即"a$"
正则 | 待匹配字符 | 匹配结果 | 说明 |
---|---|---|---|
\d | \d | False | 因为在正则表达式中\是有特殊意义的字符,所以要匹配\d本身,用表达式\d无法匹配 |
\d | \d | True | 转义\之后变成\\,即可匹配 |
"\\d" | '\d' | True | 如果在python中,字符串中的'\'也需要转义,所以每一个字符串'\'又需要转义一次 |
r'\d' | r'\d' | True | 在字符串之前加r,让整个字符串不转义 |
7、贪婪匹配与非贪婪匹配
*?, +?, ??, {m,n}?
前面的*,+,?等都是贪婪匹配,也就是尽可能匹配,后面加?号使其变成惰性匹配
满足匹配时,匹配尽可能长的字符串,默认情况下,采用贪婪匹配,加上?变成非贪婪匹配(惰性匹配)
正则 | 待匹配字符 | 匹配结果 | 说明 |
---|---|---|---|
<.*> | <script>...<script> | <script>...<script> | 默认为贪婪匹配模式,会匹配尽量长的字符串 |
<.*?> | <script>...<script> | <script><script> | 加上?为将贪婪匹配模式转为非贪婪匹配模式,会匹配尽量短的字符串 |
例子
import re
print(re.findall("<.*>","<script>...<script>")) #['<script>...<script>']
print(re.findall("<.*?>","<script>...<script>")) #['<script>', '<script>']
分析:<.*>是贪婪匹配,从左直接匹配到最右侧,然后向左回退到最后一个“>”,这就是回溯算法
"<.*?>"是非贪婪匹配,匹配时是从左向右匹配,遇到一个“>”马上返回,继续匹配,遇到一个遇到一个“>”马上返回。
几个常用的非贪婪匹配Pattern
*? 重复任意次,但尽可能少重复
+? 重复1次或更多次,但尽可能少重复
?? 重复0次或1次,但尽可能少重复
{n,m}? 重复n到m次,但尽可能少重复
{n,}? 重复n次以上,但尽可能少重复
.*?的用法
. 是任意字符
* 是取 0 至 无限长度
? 是非贪婪模式。
何在一起就是 取尽量少的任意字符,一般不会这么单独写,他大多用在:
.*?x
就是取前面任意长度的字符,直到一个x出现
(二)re模块中常用功能函数
1、compile()
编译正则表达式模式,返回一个对象的模式。(可以把那些常用的正则表达式编译成正则表达式对象,这样可以提高一点效率。)
格式
re.compile(pattern,flags=0)
pattern: 编译时用的表达式字符串。
flags 编译标志位,用于修改正则表达式的匹配方式,如:是否区分大小写,多行匹配等。常用的flags有:
标志 | 含义 |
---|---|
re.S(DOTALL) | 使.匹配包括换行在内的所有字符 |
re.I(IGNORECASE) | 使匹配对大小写不敏感 |
re.L(LOCALE) | 做本地化识别(locale-aware)匹配,法语等 |
re.M(MULTILINE) | 多行匹配,影响^和$ |
re.X(VERBOSE) | 该标志通过给予更灵活的格式以便将正则表达式写得更易于理解 |
re.U | 根据Unicode字符集解析字符,这个标志影响\w,\W,\b,\B |
补充:
- re.S:
- 使 . 匹配包括换行在内的所有字符
- re.M:
- 进行多行匹配,在新的一行中,同样可以使用^来匹配该行字符串的开头,用$来匹配该行字符串的结尾
例子
#匹配出i开头的行 string = '''fall in love with you
i love you very much
i love she
i love her'''
print(re.findall('^i.*',string,re.S))
print(re.findall('^i.*',string,re.M))
输出结果
[]
['i love you very much', 'i love she', 'i love her']
例子
import re
p = re.compile("\d+") #创建一个常用的规则
res = p.search("abc123sxajk")
print(res) #search直接返回的是一个match对象,需要调用group()方法获取匹配字符串
print(res.group())
输出结果
<_sre.SRE_Match object; span=(3, 6), match='123'>
123
2、search()
函数会在字符串内查找模式匹配,只到找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。
格式
re.search(pattern, string, flags=0)
例子
import re
res = re.search("\d+","abc123sxajk")
print(res) #search直接返回的是一个match对象,需要调用group()方法获取匹配字符串
print(res.group())
输出结果
<_sre.SRE_Match object; span=(3, 6), match='123'>
123
3、match()
同search,不过仅在字符串开始处进行匹配
格式:
re.match(pattern, string, flags=0)
例子
import re
res = re.match("\d+","123sxajk")
print(res) #match匹配要从开头处匹配,match也是直接返回的是一个match对象,需要调用group()方法获取匹配字符串
print(res.group()) #如果匹配不到返回的是None,这时调用group()方法会报错
输出结果
<_sre.SRE_Match object; span=(0, 3), match='123'>
123
分析:match()方法是从字符串的开头处匹配的,如果匹配不到则返回None,这时调用group()方法会报错,因为None没有group()方法。
*注:match和search一旦匹配成功,就是一个match object对象,而match object对象有以下方法:
group() 返回被 RE 匹配的字符串
start() 返回匹配开始的位置
end() 返回匹配结束的位置
span() 返回一个元组包含匹配 (开始,结束) 的位置
group() 返回re整体匹配的字符串,可以一次输入多个组号,对应组号匹配的字符串。
a. group()返回re整体匹配的字符串,a. group (n,m) 返回组号为n,m所匹配的字符串,如果组号不存在,则返回indexError异常a.groups()groups() 方法返回一个包含正则表达式中所有小组字符串的元组,从 1 到所含的小组号,通常groups()不需要参数,返回一个元组,元组中的元素就是正则表达式中定义的组。
4、findall()
返回所有满足匹配条件的结果,放在列表里
格式:
re.findall(pattern, string, flags=0)
import re
print(re.findall("a","abc sxa dda"))
输出结果
['a', 'a', 'a']
5、finditer()
搜索string,返回一个顺序访问每一个匹配结果(Match对象)的迭代器。找到 RE 匹配的所有子串,并把它们作为一个迭代器返回。
格式:
re.finditer(pattern, string, flags=0)
import re
res = re.finditer("\d","dak2fhr34ehnb567grd")
print(res) #返回的是一个可调用的迭代器
print(type(res))
print(next(res)) #通过迭代器的next()方法取出每个值,这里的每个值是一个match对象
print(next(res).group()) #通过调用match对象的group()方法来取出匹配出的值
输出结果
<callable_iterator object at 0x02655870>
<class 'callable_iterator'>
<_sre.SRE_Match object; span=(3, 4), match='2'>
3
6、split()
按照能够匹配的子串将string分割后返回列表。
格式:
re.split(pattern, string[, maxsplit])
import re
print(re.split("[ab]","abcdeg"))
输出结果
['', '', 'cdeg']
分析:
执行过程:首先以"a"分割字符串“abcdeg",得到结果["","bcdeg"],即一个空白字符和”bcdeg“,然后再用”b“对这个结果再次进行分割,得到['', '', 'cdeg'],即两个空白字符和‘cdeg’.
7、sub()
使用re替换string中每一个匹配的子串后返回替换后的字符串。
格式:
re.sub(pattern, repl, string, count)
例子
import re
print(re.sub("a","s","hahahah"))
输出结果
hshshsh
8、subn()
替换string中匹配子串,但返回的是元组(替换的结果,替换了多少次)
格式:
subn(pattern, repl, string, count=0, flags=0)
例子
import re
print(re.subn("a","s","hahahah"))
输出结果
('hshshsh', 3)
三、重要补充
1、findall的分组优先
如果re.findall()规则里有分组(括号),那么findall只能返回分组里的内容。
例子
res = re.findall("www.(baidu|google).com","www.google.com")
print(res)
输出结果
['google']
分析:注意这里只能匹配返回出分组里的内容,而非整体的字符串。
想要整体返回需要在分组里加?:取消分组优先模式(问号在正则表达式里的第三个功能,第一个表示匹配次数,第二个是实现惰性匹配)
import re
res = re.findall("www.(?:baidu|google).com","www.google.com")
print(res)
输出结果
['www.google.com']
2、 split的优先级
re.split()方法在加上分组之后可以返回被匹配分割去掉的项。在匹配部分加上()之后所切出的结果是不同的,没有()的没有保留所匹配的项,但是有()的却能够保留了匹配的项
例子
import re
res1 = re.split("\d+","hello5world5hi2")
res2 = re.split("(\d+)","hello5world5hi2")
print(res1)
print(res2)
输出结果
['hello', 'world', 'hi', '']
['hello', '5', 'world', '5', 'hi', '2', '']
Python之路(第二十一篇) re模块的更多相关文章
- Python之路(第二十篇) subprocess模块
一.subprocess模块 subprocess英文意思:子进程 那什么是进程呢? (一)关于进程的相关理论基础知识 进程是对正在运行程序的一个抽象,进程的概念起源于操作系统,是操作系统最核心的概念 ...
- Python开发【第二十一篇】:Web框架之Django【基础】
Python开发[第二十一篇]:Web框架之Django[基础] 猛击这里:http://www.cnblogs.com/wupeiqi/articles/5237704.html Python之 ...
- python之路第五篇之模块和加密算法(进阶篇:续)
模块 Python中,如果要引用一些内置的函数,该怎么处理呢?在Python中有一个概念叫做模块(module) 简单地说,模块就是一个保存了Python代码的文件. 模块分类: 1)内置模块 2)自 ...
- Python之路(第十七篇)logging模块
一.logging模块 (一).日志相关概念 日志是一种可以追踪某些软件运行时所发生事件的方法.软件开发人员可以向他们的代码中调用日志记录相关的方法来表明发生了某些事情.一个事件可以用一个可包含可选变 ...
- Python进阶【第十一篇】模块(下)之常用模块
内置模块是Python自带的功能,在使用内置模块相应的功能时,需要[先导入]再[使用] 一.time模块 在Python中,通常有这几种方式来表示时间: 时间戳(timestamp):通常来说,时间戳 ...
- Python学习【第十一篇】模块(1)
模块 模块让你能够有逻辑地组织你的Python代码段. 把相关的代码分配到一个模块里能让你的代码更好用,更易懂. 模块也是Python对象,具有随机的名字属性用来绑定或引用. 简单地说,模块就是一个保 ...
- Python之路(第二十三篇) 面向对象初级:静态属性、静态方法、类方法
一.静态属性 静态属性相当于数据属性. 用@property语法糖装饰器将类的函数属性变成可以不用加括号直接的类似数据属性. 可以封装逻辑,让用户感觉是在调用一个普通的数据属性. 例子 class R ...
- Python之路(第十三篇)time模块、random模块、string模块、验证码练习
一.time模块 三种时间表示 在Python中,通常有这几种方式来表示时间: 时间戳(timestamp) : 通常来说,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量.(从 ...
- Python之路(第十一篇)装饰器
一.什么是装饰器? 装饰器他人的器具,本身可以是任意可调用对象,被装饰者也可以是任意可调用对象. 强调装饰器的原则:1 不修改被装饰对象的源代码 2 不修改被装饰对象的调用方式 装饰器的目标:在遵循1 ...
随机推荐
- cakephp2.7的学习笔记1 —— 安装与配置
CakePHP2.7的安装 下载 https://github.com/cakephp/cakephp/releases 解压后扔进你的www目录就可以直接访问 按照提示,修改这两项配置,替换成你喜欢 ...
- display:none vs visibility:hidden
[display:none vs visibility:hidden] 设置元素的display为none是最常用的隐藏元素的方法. 1 .hide { 2 display:none; 3 } 将元素 ...
- 解决谷歌浏览器频繁出现adobe flash player因过期而遭到阻止的问题(转自知乎)
作者:在战争中链接:https://www.zhihu.com/question/32223811/answer/128088278来源:知乎著作权归作者所有,转载请联系作者获得授权. 很多新用户在安 ...
- typedef void (*Fun) (void) 的理解——函数指针——typedef函数指针
首先介绍大家比较熟悉的typedef int i;//定义一个整型变量i typedef myInt int: myInt j;//定义一个整型变量j 上面介绍得是我们常用的比较简单的typedef的 ...
- css3动画:执行前不显示,执行后显示
今天做一个轮播,轮播图上使用animation.需求是当滚动到当前图片时,图片中的div从无到有逐渐显示, 遇到的问题是:页面刷新时,此图片上的div可以从无到有,但第二次滚动到此图片时,总是先显示一 ...
- 如何开发简单的javaweb项目,jsp+javabean+servlet
一.相关的软件下载和环境配置 1.下载并配置JDK. 2.下载eclipse. 3.下载并配置apache-tomcat(服务器). 4.下载MySQL(数据库). 5.下载Navicat for M ...
- AngularJS——第1章 简介
第1章 简介 由谷歌公司开发维护的前端MVC框架,克服了HTML在构建应用上的诸多不足,降低了开发成本,提高了效率. 一个框架 以数据和逻辑作为驱动 AngularJS核心特性:模块化,双数据绑定,语 ...
- (八) .launch文件 ---编写简单的启动脚本文件
下面我们将介绍,如何编写一个启动脚本程序:(.launch文件) 还记得我们在 创建ROS软件包教程 中创建的第一个程序包(beginner_tutorials)吗,现在我们要使用它. 在 begin ...
- springboot报错Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactory bean
springboot项目在启动时需要把servlet容器编译进去,这时候如果你的maven依赖里面没有配置jetty或者tomcat相关依赖就会报错. 解决方法: jetty添加 <depend ...
- angular 1.x 控制器之间互相传递参数
我们要向前方看齐,基于js引用类型的对象就不记了,所以使用基于事件的方式: angular 中 $on,$emit,$boardcast来实现父控制器和子控制器互相通讯, 其中$on表示事件监听, $ ...