一篇文章学会正则表达式

作者在学正则表达式的时候多走了很多弯路,在网上也看了很多文章。这篇文章的目的就是让大家少走一些弯路,争取看完这篇文章就能对正则表达式有一个正确的认识,并且能够初步掌握正则表达式。当然那么多表达式是不可能一下就记下来的,因此这篇文章也相当于作者的一个笔记,以后需要的时候可以回来看看。

正则表达式

正则表达式是什么

在我们日常生活中,经常会遇到需要查找某些复杂字符串的情况,比如我们在一篇文章中查找所有的形如010-12345678的电话号码,这种字符串都是三位数字加上‘-’再加上八位数字的形式,这时候就需要用到正则表达式了。在我的简介中,正则表达式是一个模板,所有符合模板形式的字符串都会被它捕获。正则表达式中有一个很重要的定义叫做元字符,例如‘\b’,‘\w’等,在下面会介绍这些元字符使用来干什么的以及怎么使用。

元字符

字符 说明 实例
. 匹配除了换行符之外的任意字符 b.t可匹配bat,but等
\w 匹配字母或数字或汉子或下划线 b\wt可匹配bat,b1t等
\s 匹配空白符(空格、TAB、换行符) b\st可匹配b t
\d 匹配数字 b\dt可匹配b1t等
\b 匹配单词的边界 \bgiao\b匹配单词giao
^ 匹配字符串的开始 ^The匹配The开始的字符串
$ 匹配字符串的结束 ing$匹配以ing结尾的字符串

字符转义

因为“.” ,“\” ,“*”等元字符在正则表达式中都有自己独特的含义,因此我们如果查找它们就容易发生混淆,因此我们如果要查找它们就在它们前面加上一个转义符“\”。要查找‘.’你就写‘.’,以此类推。

重复

符号 说明
1. 重复零次或更多次
2. 重复一次或更多次
? 重复零次或一次
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n到m次

下面我会用一些例子来使这易于理解。
如果我们想查找一个开头是ac,结尾是ing,中间任意几位字母或数字的字符串,我们的正则表达式应该是ac\w*ing
如果我们想匹配刚好6位的单词,我们的正则表达式应该是\b\w{6}\b
如果我们相想匹配QQ号(5到10位),我们的正则表达式应该是^\d{5,10}$
结合例子来看应该是很易于理解的

字符类

但是如果我们想查找一些没有预先定义的字符,比如我们既就要查找一串‘-=+*’的字符串,我们应该怎么办。很简单,直接用[-=+*]表示即可。
比如我们要查找形如(010)-12345678的字符串,我们的正则表达式应该是这样的(\w{3}[)-]\w{8},这也是易于理解的

分支条件

有时候我们需要查找多种条件下的字符串,这时候我们的正则表达式就需要使用分支条件‘|’.其实很容易理解,我举个例子你就明白了
我们想要匹配两种号码,一种是三位区号加号码012-12345678,另一种是四位区号加号码0123-12345678,正则表达式应该是这样的
0\d{2}-\d{8}|0\d{3}-\d{8}。只需要在两个正则表达式中间加一个|即可

分组

在之前我们已经学会了令单个字符进行重复,但是我们如果想让多个字符进行重复,我们就需要使用到分组了。分组其实就是用‘()’把一些字符括起来。
例子:**(\d{1,3}.){3}\d{1,3}**这个正则表达式表示的是一个简易的地址表示,它的结构是1-3位数字加英文句号重复三次,再加上1-3位数字

反义

之前我们会匹配数字了,用\d就行,但是如果我要你查找所有非数字,应该怎么做呢,这时候就需要用到反义。反义其实很简单,你想要谁的反义就将它的元字符大写,当然也有例外。

符号 说明
\W 匹配任意不是字母,数字,下划线,汉字的字符
\S 匹配任意不是空白符的字符
\D 匹配任意非数字的字符
\B 匹配不是单词开头或结束的位置
[^x] 匹配除了x以外的任意字符
[^aeiou] 匹配除了aeiou这几个字母以外的任意字符

就像表格写的一样,意思很易于理解

后向引用

不咋好理解,只有几种用法记下来就行。
重复搜索前面某个分组内的文本,\1代表1分组,同理\2就代表2分组,
简单来说组号的分配就是从左向右扫一遍依次编号,但是实际上是扫两遍的,第一遍先扫未命名分组,第二遍再扫命名分组,所以命名分组的组号总是比未分组的组号高。

代码/语法 说明
(exp) 匹配exp,并捕获文本到自动命名的组里
(?exp) 匹配exp,并捕获文本到名称为name的组里,也可以写成(?'name’exp)
(?:exp) 匹配exp,不捕获匹配的文本,也不给此分组分配组号

接下来将对这三种情况一一进行解释

(1)还是从例子来说:\b(\w+)\b\s+\1\b可以用来匹配重复的单词,像go go, 或者kitty kitty。怎么理解这个表达式呢,首先\b(\w+)\b表示的是一个单词,括号中的东西也就被标记为了1分组,之后的\s+表示一个或多个空格,\1表示的自然就是1分组。这是没有命名的分组
(2)要指定一个子表达式的组名,请使用这样的语法:(?\w+)(或者把尖括号换成’也行:(?‘Word’\w+)),这样就把\w+的组名指定为Word了。要反向引用这个分组捕获的内容,你可以使用\k,所以上一个例子也可以写成这样:
\b(?\w+)\b\s+\k\b
(3)(?:exp)不会改变正则表达式的处理方式,只是这样的组匹配的内容不会像前两种那样被捕获到某个组里面,也不会拥有组号。

零宽断言

代码 说明
(?=exp) 匹配exp前面的位置
(?<=exp) 匹配exp后面的位置

例子真是万金油。。。还是用例子来进行说明
(?=exp)也叫零宽度正预测先行断言,它断言自身出现的位置的后面能匹配表达式exp。比如\b\w+(?=ing\b),匹配以ing结尾的单词的前面部分(除了ing以外的部分),如查找I’m singing while you’re dancing.时,它会匹配sing和danc。

(?<=exp)也叫零宽度正回顾后发断言,它断言自身出现的位置的前面能匹配表达式exp。比如(?<=\bre)\w+\b会匹配以re开头的单词的后半部分(除了re以外的部分),例如在查找reading a book时,它匹配ading。

负向零宽断言

零断宽言是我们用来匹配“是某字符串exp”的,那么倘若我们想匹配“不是某字符exp”的,我们就要用到负向零宽断言了。

代码 说明
(?!exp) 匹配后面跟的不是exp的位置
(?<!exp) 匹配前面不是exp的位置

(?!exp)叫做零宽度负预测先行断言,是匹配断言位置后面包含exp的,例子:\d{3}(?!\d)匹配三位数字,而且这三位数字的后面不能是数字。
(?<!exp)叫做零宽度负回顾后发断言,跟上面那家伙相反。例如:(?<![a-z])\d{7}匹配前面不是小写字母的七位数字。

注释

一种语法:用“(?#comment)”来包含注释。例如:2[0-4]\d(?#200-249)|250-5|[01]?\d\d?(?#0-199)。括号里的东西也就被注释掉了。

贪婪匹配与懒惰匹配

我们要知道,如果我们的正则表达式是a.b,那么系统会匹配a和b中间最长的一个字符串,这也就是所说的贪婪匹配
但是有时候我们想要尽可能短的,那就需要让它懒惰下来,我们只需要在其后面加一个?就行,a.
?b就会匹配尽可能短的字符串,这就是懒惰匹配

平衡组

鹅不会,自行百度,其实学到这你已经基本掌握了正则表达式的内容了。。。。

Python中使用正则表达式

Python提供了re模块来进行正则表达式的相关操作,下面是re模块的核心函数

函数 说明
compile(pattern, flags=0) 编译正则表达式返回正则表达式对象
match(pattern, string, flags=0) 用正则表达式匹配字符串 成功返回匹配对象 否则返回None
search(pattern, string, flags=0) 搜索字符串中第一次出现正则表达式的模式 成功返回匹配对象 否则返回None
split(pattern, string, maxsplit=0, flags=0) 用正则表达式指定的模式分隔符拆分字符串 返回列表
sub(pattern, repl, string, count=0, flags=0) 用指定的字符串替换原字符串中与正则表达式匹配的模式 可以用count指定替换的次数
fullmatch(pattern, string, flags=0) match函数的完全匹配(从字符串开头到结尾)版本
findall(pattern, string, flags=0) 查找字符串所有与正则表达式匹配的模式 返回字符串的列表
finditer(pattern, string, flags=0) 查找字符串所有与正则表达式匹配的模式 返回一个迭代器
purge() 清除隐式编译的正则表达式的缓存
re.I / re.IGNORECASE 忽略大小写匹配标记
re.M / re.MULTILINE 多行匹配标记

下面给出一个例子,剩下的还需要多动手来进行参悟

"""
验证输入用户名和QQ号是否有效并给出对应的提示信息

要求:用户名必须由字母、数字或下划线构成且长度在6~20个字符之间,QQ号是5~12的数字且首位不能为0
"""
import re


def main():
    username = input('请输入用户名: ')
    qq = input('请输入QQ号: ')
    # match函数的第一个参数是正则表达式字符串或正则表达式对象
    # 第二个参数是要跟正则表达式做匹配的字符串对象
    m1 = re.match(r'^[0-9a-zA-Z_]{6,20}$', username)
    if not m1:
        print('请输入有效的用户名.')
    m2 = re.match(r'^[1-9]\d{4,11}$', qq)
    if not m2:
        print('请输入有效的QQ号.')
    if m1 and m2:
        print('你输入的信息是有效的!')


if __name__ == '__main__':
    main()
    例子来源自https://github.com/jackfrued/Python-100-Days/blob/master/Day01-15/12.%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%92%8C%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F.md
发布了14 篇原创文章 · 获赞 15 · 访问量 1340

猜你喜欢

转载自blog.csdn.net/weixin_45939019/article/details/104094888
今日推荐