一、初始

在编程中,字符串往往是我们用到的最多的一类数据结构,但有时十分复杂的字符串处理起来往往十分令人头疼,为了更好的实现对高级文本进行匹配、抽取、搜索、替换等功能,正则表达式(简称为regex)应运而生;

什么是正则表达式呢?

简单的说,正则表达式是一些由字符和特殊符号组成的字符串,它们描述了一种模式或者多种模式或者仅仅是用来表述几个字符;

那么肯定又有人问了,什么是模式?

模式是用来匹配字符串的模板,一种模式可能会匹配到多个符合条件的字符串;比如我随便写一个模式:bit ,按照模式 bit 会匹配到的字符串也只可能是 bit ,因为这个模式没有特殊符号,它描述的字符串也十分精准,即只可能是 bit ;但如果我再写一个模式 b[a-z]t ,可以看到这个模式很明显与上一个有很大区别,在它里面添加了特殊符号 [] 以及 - ,那么它匹配到的将是 bat、bbt、bct…bzt 中任何一个皆有可能。
正则表达式中有十分多的特殊符号,通过学习它们,我们可以匹配出很多复杂的字符串结构并且得到我们想要的结果;

那么怎么匹配呢?

在讨论与字符串模式相关的正则表达式时,匹配指的是模式匹配,而在Python中,主要有两种方法完成模式匹配,即:
匹配(match)搜索(search)
关于它们的具体用法将在下文进行展示;

二、特殊符号

上面讲到,正则表达式有许多特殊符号,它们使得正则表达式灵活多变,充满活力,学习这些特殊符号的用法是学习正则表达式的必经路径,下面将介绍正则表达式中最常见的特殊符号与字符;

1.择一匹配符

择一匹配符 (|) 表示从多个模式中任选其一的操作;

示例:

模式 匹配的字符串
bug|big|pig bug、big、pig
42a|27d 42a、27d

2.句点匹配符

句点匹配符 (.) 匹配除了换行符\n之外的任何字符,注意是任何字符,不局限于字母和数字、或者可打印字符、不可打印字符;另外,在Python的正则表达式中有一个编译标记,该标记可以使句点匹配符匹配换行符;

示例:

模式 匹配的字符串
s.x 匹配长度为3的字符串,且开头和结尾是s和x,可以是six、sxx、sex等等
匹配任意三个字符
\. 通过转义符匹配句点

3.边界匹配符

边界匹配符用于在字符串的起始或者结尾部分指定用于搜索的模式,涉及到的特殊字符有:
匹配字符串的开始位置:(^) 或者 (\A) ;
匹配字符串的末尾位置:($) 或者 (\Z) ;

示例:

模式 匹配的字符串
^Hello 匹配任何以Hello作为起始的字符串
Byebye$ 匹配任何以Byebye作为结尾的字符串
^b7.27$ 匹配任何由b7.27组成的单独字符串

特殊字符 (\b)、(\B) 也用来匹配字符边界
(\b) 用于匹配单词的开头和结尾,也就是边界部分;
(\B) 用于匹配单词的中间部分,非边界部分;

示例:

模式 匹配的字符串
\bnice 匹配nice前有边界的字符串
nice\b 匹配nice结尾有边界的字符串
\bnice\b 匹配nice单独字符串
\Bnice 匹配任何包含nice但不以nice作为边界的字符串

4.字符集

方括号 ([]) 用于创建一个字符集,这种正则表达式能够匹配方括号中的任何字符;

示例:

模式 匹配的字符串
[bp][iu]g big、bug、pig、pug

附加:
(-) : 限定范围的特殊符号;
([^) : 在字符集中表否定的特殊符号;

示例:

模式 匹配的字符串
[2000-2018]-[1-12]-[1-31] 匹配2000-5-20等所有满足条件的表日期的特殊字符串
[^\t\n] 不匹配制表符或者换行符

5.闭包操作符

(*) :匹配零次或者多次出现的正则表达式;
(+) : 匹配一次或者多次出现的正则表达式,也叫正闭包操作符;
(?): 匹配零次或者一次出现的正则表达式;
({}): 匹配指定次数或指定范围出现的正则表达式

示例:

模式 匹配的字符串
[bp]i[gt]? 先匹配b或者p,紧跟i,后面最多一个g或者t:bi、pi、big、bit、pig、pit
[0-9]{9,10} 匹配9个或者10个数字,可能是qq号码等
[0-9]+.[0-9]* 匹配表示浮点数的字符串

6.特殊字符表示字符集

一些特殊符号可以表示一个字符集,比如:
(\d) :表示字符集 [0-9];
(\w) :表示字符集 [a-zA-Z0-9_];
(\s) :表示空格字符,包括Tab等空白符;
以上特殊字符的大写版本表示不匹配,比如 \D 表示字符集 [^0-9];

7.使用圆括号指定分组

有时我们想把匹配到的字符串分组存储或者处理,这时使用圆括号分别包裹相应的正则表达式;
在正则表达式中,一对圆括号可以实现以下功能

  • 对正则表达式进行分组;
  • 匹配子组;

关于分组的更详细用法下面会结合实例介绍;

8.拓展表示法

拓展表示法通常用于在判断之前提供标记,实现预匹配或者条件检查的功能;
拓展表示法的使用符号为 (?..),需要注意的是拓展表示法虽然用到了括号,但是它不具备分组的功能;
示例:

模式 匹配的字符串
(?:\w+.)* 匹配以句点作为结尾的字符串,但这些匹配不会被保存下来
(?#comment) 此处不匹配,只作为注释
(?=.com) 如果一个字符串后面跟着.com才做匹配操作
(?!.net) 如果一个字符串后面不是.net才做匹配操作
(?<=abc) 如果一个字符串之前为abc才做匹配

三、Python与正则表达式

正则表达式的基本知识已经输送完毕,那么接下来让我们利用Python来应用它们;
首先呢,Python当然是支持正则表达式的,Python通过re模块来支持正则表达式,下面就来学习这个模块;

Python的re模块里面有许多常见的函数和方法,接下来将由重及轻的逐一介绍并辅以示例;

1.match()与search()

match()与search()都是用于模式匹配的函数,它们两个的主要区别在于:
match()总是试图从字符串的开始位置进行匹配,而search()总是试图在字符串的任意位置开始匹配;

对match()函数,如果匹配成功,返回匹配对象,否则返回None
使用示例:

import re
m = re.match('mate','mates')
if m is not None:print(m.group())print(type(m)))
##
mate
<class 're.Match'>

可以看到成功匹配出字符串bit并返回该匹配对象,该匹配对象的类型为 re.Match,输出匹配对象的内容时,使用了方法group(),关于group()下面会提到,现在只需要知道它的功能是返回对象的内容,如果只是单纯的使用print(m)的话,输出的将是带参数的re.Match object的说明;

注意到这里额外有一条if判断语句,只有m不是None才使用group()方法输出,因为None没有group()方法,这样做可以避免匹配失败时导致程序的AttributeError错误;

参照示例:

import re
print(re.match('mate','mates').group()))

另外,由于match()是从头匹配,所以很容易产生匹配错误,如下:

import re
m = re.match('mate','classmate')
if m is not None:print(m.group())

这段程序运行后无输出,因为match()在classmate的开头找不到mate;

这时就需要用到search()函数了:

m = re.search('mate','classmate')
if m is not None:print(m.group()) #mate

2.group()与groups()方法

group()与groups()都是正则匹配对象的方法,即 re.Match object方法

group()用于返回整个匹配对象,或者根据要求返回特定子组;
groups()则仅返回一个包含唯一或者全部子组的元组;

这里注意的是,如果没有子组要求,那么groups()将返回一个空元组

示例:

s = 'pig|bug|bit|'
m = re.match(s,'pigduang')
print(m.group())
print(m.groups())
##
pig
()s = '(\d+)(\.\d*)' #这里用到了()将正则表达式分组,本例即把整数部分与小数部分分组
m = re.match(s,'9.727')
print(m.group())
print(m.groups())
##
9.727
('9', '.727')

另外,其实group()方法也能够访问子组,通过传入参数,其中1表示输出第一个子组,以此类推:

s = '(\d+)(\.\d*)'
m = re.match(s,'9.727')
print(m.group(1))
print(m.group(2))
##
9
.727

3.\b 与 \B

对于上文提到的正则表达式中的边界符号 (\b)与(\B),这里结合示例再进行一个说明:

m = re.search(r'\bpen','The pen is mine') #因为单词pen前面有边界,这里的边界指除字母、数字、下划线之外的其它字符
if m is not None:print(m.group()) #penm = re.search(r'\bpen','Thepen is mine')
if m is not None:print(m.group()) #pen前无边界,无输出m = re.search(r'pen\b','Thepen is mine') #pen后有边界,成功输出
if m is not None:print(m.group()) #pen \B用法与之类似,不再赘述

4.compile()函数

在Python中,字符串想要使用是需要经过Python解释器的编译的,每一次使用,Python解释器都会把字符串对象编译成代码对象,这样的话可想而知,如果对于某一字符串需要重复调用,那么将造成效率的折损,这时可以借用eval()函数预编译来提高性能,这是因为预编译的代码对象使用起来要比直接使用字符串要快的缘故;
预编译对于需要重复使用的对象往往很有用,当然这对正则表达式对象也是;提供给正则表达式预编译功能的是re模块下的compile()函数:

s = re.compile(r'\w+\.\w+\.com')
print(type(s))
m = re.search(s,'www.bilibili.com')
print(type(m))
print(m.group())
##
<class 're.Pattern'> #被编译后的类型为 re.Pattern
<class 're.Match'>
www.bilibili.com

5.findall()与finditer()函数

findall():
findall()查询字符串中某个正则表达式模式全部的非重复出现情况,并返回一个列表,如果未找到匹配部分,就返回空列表

示例:

print(re.findall('gen','gen'))
#['gen']print(re.findall('gen','a generous general'))
#['gen', 'gen']

可以看到,findall()返回的列表将包含字符串中每一个成功匹配到的部分;这也是它与match()与search()的不同之处,findall会匹配字符串中的所有,但是match()和search()只要匹配成功就不会再管剩下的还没有匹配的部分,比如:

print(re.search('gen','a generous general').group())
#gen

当正则表达式指定子组的话,那么将返回一个元组列表

import re
print(re.findall('(ge(n))','a generous general'))
#[('gen', 'n'), ('gen', 'n')]

另外注意:

s = 'this and that'
print(re.findall(r'(th\w+)',s)) #['this', 'that']
print(re.findall(r'(th\w+) and (th\w+)',s))  #[('this', 'that')]
#以上两种方式注意区分

finditer():
finditer()函数与findall类似,只不过它返回一个迭代对象,这样做的目的则是为了节省内存;
示例:

s = 'this and that'
print(next(re.finditer(r'(th\w+) and (th\w+)',s)))
#<re.Match object; span=(0, 13), match='this and that'>
#注意next()调用迭代器后返回的是一个正则匹配对象,仍是无法直接输出数据的,因此可以:s = 'this and that'
print(next(re.finditer(r'(th\w+) and (th\w+)',s)).groups())
#('this', 'that')#也可以用group()
s = 'this and that'
print(next(re.finditer(r'(th\w+) and (th\w+)',s)).group(1))
#this#也可以用for循环遍历迭代器
s = 'this and that'
for g in re.finditer(r'(th\w+) and (th\w+)',s):print(g.groups())
##
('this', 'that')

1-5、附加:
以上所提到的函数,即search()、match()、compile()、findall()、finditer()函数,除了上面介绍的常用使用方法外,它们都还有第三个参数flags,flags可以指定,也可以不指定,它主要是用来提供其它附加条件,比如不区分大小写的匹配或者让句点匹配符能够匹配回车符等等,具体使用可以参阅官方说明文档;

6.sub()与subn()函数

sub()与subn()函数用于实现搜索与替换功能,先来看sub():

sub():
语法格式:

re.sub(pattern,repl,string,count=0,flags=0)
  • pattern :模式字符串,即正则表达式;
  • repl :替换的字符串,也可以是一个函数;
  • string :原字符串;
  • count :替换的次数,默认为0,即匹配并替换全部;
  • flags :编译时用的匹配模式;

示例:

print(re.sub(r'Mr\.\w+','Ms.White','Hello,Mr.Black'))
#Hello,Ms.White

subn():
subn()几乎和sub()一样,唯一不同的是,subn()不仅返回替换后的字符串,还将替换次数返回,这两个返回值作为一个元组返回;

print(re.subn(r'Mr\.\w+','Ms.White','Hello,Mr.Black'))
#('Hello,Ms.White', 1)

7.split()函数:

re.split()与str.split()都是分割字符串的,但re.split()是基于正则表达式之上对字符串进行分割,它能够处理更加复杂的字符串结构,这点是str.split()无法比拟的;
语法格式:

re.split(pattern,str,maxsplit=0,flags=0)

后两个参数可选:

  • pattern :正则表达式;
  • str :待分割字符串;
  • maxsplit :分割次数,默认为0,即不限制次数;
  • flags :控制匹配方式;

示例:

s = '130-001@abc.opk'
print(re.split('-|@|\.',s))
#['130', '001', 'abc', 'opk']

参考
《Python核心编程》
菜鸟编程
廖雪峰的官方网站

Python与正则表达式相关推荐

  1. Python中正则表达式用法 重点格式以这个为准_首看_各种问题

    20210811 https://www.jb51.net/article/101258.htm 一.惰性模式的概念: 此模式和贪婪模式恰好相反,它尽可能少的匹配字符以满足正则表达式即可,例如: va ...

  2. python使用正则表达式判别字符串是否以一个大写字符起始而跟随了一些小写字符

    python使用正则表达式判别字符串是否以一个大写字符起始而跟随了一些小写字符 # # Python3 code to find sequences of one upper # case lette ...

  3. python使用正则表达式统计字符串中出现次数最多的数字

    python使用正则表达式统计字符串中出现次数最多的数字 #python使用正则表达式统计字符串中出现次数最多的数字 # find the most occurring element import ...

  4. python使用正则表达式识别大写字母并在大写字母前插入空格

    python使用正则表达式识别大写字母并在大写字母前插入空格 #python使用正则表达式识别大写字母并在大写字母前插入空格 import redef putSpace(input):# regex ...

  5. python使用正则表达式删除字符串中的其它字符只保留数字和字母

    python使用正则表达式删除字符串中的其它字符只保留数字和字母 #python使用正则表达式删除字符串中的其它字符只保留数字和字母 # Python code to demonstrate # to ...

  6. python使用正则表达式寻找具有特定后缀的文件

    python使用正则表达式寻找具有特定后缀的文件 # python使用正则表达式寻找具有特定后缀的文件 # import library import re# list of different ty ...

  7. python使用正则表达式抽取字符串中最大数值数字

    python使用正则表达式抽取字符串中最大数值数字 #python使用正则表达式抽取字符串中最大数值数字 # Function to extract maximum numeric value fro ...

  8. python使用正则表达式去除句子中的重复词

    python使用正则表达式去除句子中的重复词 #python使用正则表达式去除句子中的重复词 # Python program to remove duplicate words # using Re ...

  9. python使用正则表达式检测给定的URL地址是否合法

    python使用正则表达式检测给定的URL地址是否合法 # python使用正则表达式检测给定的URL地址是否合法 # python使用正则表达式检测给定的URL地址是否合法 # Check if a ...

  10. python使用正则表达式验证邮箱地址语法有效性

    python使用正则表达式验证邮箱地址语法有效性 #python使用正则表达式验证邮箱地址语法有效性 import re # mail regular expression formula# rege ...

最新文章

  1. Android RecyclerView(和SnapHelper) 实现类似ViewPager的效果
  2. 架构选型必读:集中式与分布式全方位优劣对比
  3. ufldl matlab 工具箱,matlab的Deep Learning的toolbox 中的SAE算法
  4. Python3 From Zero——{最初的意识:007~函数}
  5. 和电商有关的词语_电商描写的词语 形容“电”的词语有哪些?
  6. [ECharts]echarts/config is not exists
  7. jquery和php上传文件进度条,jQuery实现文件上传进度条特效_jquery
  8. python h5s文件 压缩_如何用python解压zip压缩文件
  9. highlighting v5.0插件使用 一(持续更新)
  10. 安装多个win10系统
  11. 普元EOS常见问题及处理经验
  12. 酷开系统上线共抗疫情版块
  13. MySQL创建表和约束条件(四)
  14. kubeadm重新生成admin.conf
  15. 用Python制作二维码
  16. 原生JavaScript盒子的移动
  17. 如何安装wordcloud?
  18. input标签checkbox选中触发事件的方法
  19. codeforces 1509 B. TMT Document
  20. N1盒子内置双系统最新 V3.9.9.5 默认1920x1080分辨率版发布

热门文章

  1. 【Linux】冯诺依曼体系结构和操作系统概念
  2. 【MySQL】MySQL的自然连接和USING连接详细总结
  3. Ubuntu下tar命令使用详解 .tar解压、.tar压缩
  4. 响应式五金机械网站pbootcms模板,蓝色营销型五金配件网站源码下载
  5. 计算机专业毕业典礼,计算机网络技术专业毕业典礼发言稿
  6. 我支持刘翔,理由有三
  7. Code Review的基本思路
  8. github开源:企业级应用快速开发框架CIIP WEB+WIN+移动端
  9. java.util.Optional
  10. Autolayout的一点理解