博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Python之路(第二十一篇) re模块
阅读量:5968 次
发布时间:2019-06-19

本文共 9261 字,大约阅读时间需要 30 分钟。

 

一、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("<.*>","

  

分析:<.*>是贪婪匹配,从左直接匹配到最右侧,然后向左回退到最后一个“>”,这就是回溯算法

"<.*?>"是非贪婪匹配,匹配时是从左向右匹配,遇到一个“>”马上返回,继续匹配,遇到一个遇到一个“>”马上返回。

 

几个常用的非贪婪匹配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

例子

 
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()方法来取出匹配出的值

  

输出结果

 
<_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', '']

  

 

转载于:https://www.cnblogs.com/Nicholas0707/p/9115933.html

你可能感兴趣的文章
Web service (一) 原理和项目开发实战
查看>>
跑带宽度多少合适_跑步机选购跑带要多宽,你的身体早就告诉你了
查看>>
深入理解Java的接口和抽象类
查看>>
Javascript异步数据的同步处理方法
查看>>
iis6 zencart1.39 伪静态规则
查看>>
SQL Server代理(3/12):代理警报和操作员
查看>>
Linux备份ifcfg-eth0文件导致的网络故障问题
查看>>
2018年尾总结——稳中成长
查看>>
度量时间差
查看>>
通过jsp请求Servlet来操作HBASE
查看>>
Shell编程基础
查看>>
Shell之Sed常用用法
查看>>
Centos下基于Hadoop安装Spark(分布式)
查看>>
3D地图的定时高亮和点击事件(基于echarts)
查看>>
mysql开启binlog
查看>>
设置Eclipse编码方式
查看>>
分布式系统唯一ID生成方案汇总【转】
查看>>
并查集hdu1232
查看>>
Mysql 监视工具
查看>>
Linux Namespace系列(09):利用Namespace创建一个简单可用的容器
查看>>