python re模块

正则表达式(可以称为REs,regex,regex pattens)是一个小巧的,高度专业化的编程语言,它内嵌于python开发语言中,可通过re模块使用。正则表达式的pattern可以被编译成一系列的字节码,然后用C编写的引擎执行。

常用正则表达式符号,基本上,包含了90%的场景。

'.'

默认匹配除\n之外的任意一个字符,若指定flag DOTALL,则匹配任意字符,包括换行

'^'

匹配字符开头,若指定flags MULTILINE,这种也可以匹配上(r"^a","\nabc\neee",flags=re.MULTILINE)

'$'

匹配字符结尾,或e.search("foo$","bfoo\nsdfsf",flags=re.MULTILINE).group()也可以

'*'

匹配*号前的字符0次或多次,re.findall("ab*","cabb3abcbbac")  结果为['abb', 'ab', 'a']

'+'

匹配前一个字符1次或多次,re.findall("ab+","ab+cd+abb+bba") 结果['ab', 'abb']

'?'

匹配前一个字符1次或0次

'{m}'

匹配前一个字符m次

'{n,m}'

匹配前一个字符n到m次,re.findall("ab{1,3}","abb abc abbcbbb") 结果'abb', 'ab', 'abb']

'|'

匹配|左或|右的字符,re.search("abc|ABC","ABCBabcCD").group() 结果'ABC'

'(...)'

分组匹配,re.search("(abc){2}a(123|456)c", "abcabca456c").group() 结果 abcabca456c

'\A'

只从字符开头匹配,re.search("\Aabc","alexabc") 是匹配不到的

'\Z'

匹配字符结尾,同$

'\d'

匹配数字0-9

'\D'

匹配非数字

'\w'

匹配[A-Za-z0-9]

'\W'

匹配非[A-Za-z0-9]

's'

匹配空白字符、\t、\n、\r , re.search("\s+","ab\tc1\n3").group() 结果 '\t'

'(?P<name>...)'

分组匹配

最常用的匹配语法

re.match 从头开始匹配
re.search 匹配包含
re.findall 把所有匹配到的字符放到以列表中的元素返回
re.splita 以匹配到的字符当做列表分隔符
re.sub      匹配字符并替换

反斜杠的困扰 与大多数编程语言相同,正则表达式里使用"\"作为转义字符,这就可能造成反斜杠困扰。假如你需要匹配文本中的字符"\",那么使用编程语言表示的正则表达式里将需要4个反斜杠"\\\\":前两个和后两个分别用于在编程语言里转义成反斜杠,转换成两个反斜杠后再在正则表达式里转义成一个反斜杠。Python里的原生字符串很好地解决了这个问题,这个例子中的正则表达式可以使用r"\\"表示。同样,匹配一个数字的"\\d"可以写成r"\d"。有了原生字符串,你再也不用担心是不是漏写了反斜杠,写出来的表达式也更直观。

举个列子:

匹配以Chen开头的字符串

import re
result = re.match("^Chen","ChenLong")
print(result)

执行输出

_sre.SRE_Match object; span=(0, 4), match='Chen'

结果是一个匹配对象,请注意结尾的match='Chen' 表示匹配出了Chen

如果没有匹配上,结果为None

打印匹配结果,使用group()方法查看

print(result.group())

执行输出 Chen

注意:如果没有匹配上,使用group()会报错。

上面的正则匹配规写死了,比如^Chen 这种需求,用in方法就可以实现了。

下面说一个简单的例子

匹配以Chen开头的以及后面的数字

import re
result = re.match("^Chen\d","Chen356Long")
print(result.group())

执行输出

Chen3

注意:

\d 表示匹配一个数字

如果想要匹配多个数字,使用\d+

import re
result = re.match("^Chen\d+","Chen356Long")
print(result.group())

执行输出

Chen356

匹配任意字符.+

res = re.match(".+","Chen321Long123")
print(res.group())

执行输出

Chen321Long123

匹配单个字符.

res = re.match(".","Chen321Long123")
print(res.group())

执行输出: C

匹配Long

res = re.match("^L.+g","Chen321Long123")
print(res)

执行输出: None

为什么呢?因为match是从左至右匹配,由于Long在字符串的中间,写任何正则都无法匹配出Long。

需要用到另外一个方法search,表示从整个文本中去搜索。结果只会返回一次,如果有多个结果,会返回第一个结果。

res = re.search("L.+g","Chen321Long123")
print(res.group())

执行输出: Long

如果使用L.+g$ 是匹配不到Long的,为什么呢?

$表示匹配整个字符串的结尾,而结尾是3。由于123不是我想要的,所以不能写g$

由于.+是匹配任意字符,如果只想匹配字母呢?使用[a-z]

res = re.search("L[a-z]+g","Chen321Long123")

匹配所有字母大小写呢?使用[a-zA-Z]

res = re.search("L[a-zA-Z]+g","Chen321Long123")

匹配jack

res = re.search("[a-z]+k","123#tom#jack#rose")
print(res)

执行输出:

_sre.SRE_Match object; span=(8, 12), match='jack'

'?' 匹配前一个字符1次或0次

匹配字母a

res = re.search("a?","alin")
print(res)

执行输出:

_sre.SRE_Match object; span=(0, 1), match='a'

匹配字母a

res = re.search("a?","lina")
print(res)

执行输出:

_sre.SRE_Match object; span=(0, 0), match=''

结果显示没有匹配上,请注意,? 可以匹配0次,也就是不匹配的情况。所以它的结果不是None

'?' 匹配前一个字符1次或0次

匹配aa或者aaa

res = re.search("aaa?","aalinaaa")
print(res)

执行输出:

_sre.SRE_Match object; span=(0, 2), match='aa'

请注意aaa? 需要拆分一下aa和aaa? 为什么呢? '?'是匹配0次或者1次数

aaa?匹配0次就是aa,匹配1次,就是aaa?

'{m}' 匹配前一个字符m次

匹配3个数字

res = re.search("[0-9]{3}","aa1x2a345aa")
print(res)

执行输出:

_sre.SRE_Match object; span=(6, 9), match='345'

匹配1到3次

res = re.search("[0-9]{1,3}","aa1x2a345aa")
print(res)

执行输出:

_sre.SRE_Match object; span=(2, 3), match='1'

匹配所有数字

res = re.search("[0-9]+","aa1x2a345aa")
print(res)

执行输出:

_sre.SRE_Match object; span=(2, 3), match='1'

为什么只有一个1呢?因为search只会返回一个结果,后续的不再返回。这个时候,需要用到findall方法

注意:findall没有group()方法

res = re.findall("[0-9]+","aa1x2a345aa")
print(res)

执行输出:

['1', '2', '345']

所有的数字,都匹配出来了。

只匹配第3次的结果

res = re.findall("[0-9]{3}","aa1x2a345aa")
print(res)

执行输出:

['345']

'|' 匹配|左或|右的字符

匹配abc或者ABC

res = re.findall("abc|ABC","ABCBabcCD")
print(res)

执行输出:

['ABC', 'abc']

'(...)'分组匹配

匹配abc,在匹配c 2次

res = re.search("abc{2}","xiabccc")
print(res)

执行输出:

_sre.SRE_Match object; span=(2, 6), match='abcc'

复杂的例子

匹配abc 2次,匹配||= 2次。注意:\| 转义了,表示|

res = re.search("(abc){2}(\|\|=){2}","abcabc||=||=")
print(res)

执行输出:

_sre.SRE_Match object; span=(0, 12), match='abcabc||=||='

'\A'只从字符开头匹配

'\Z'匹配字符结尾,同$

'\A' 效果和'^' 是一样的。

匹配以数字开头,字母结尾

res = re.search("\A[0-9]+[a-z]\Z","123a")
print(res)

执行输出:

_sre.SRE_Match object; span=(0, 4), match='123a'

'\d' 匹配数字

res = re.search("\A\d+[a-z]\Z","123a")
print(res)

执行输出:

_sre.SRE_Match object; span=(0, 4), match='123a'

'\D' 匹配非数字

匹配非数字

res = re.search("\D+","123a$ -\n")
print(res)

执行输出:

_sre.SRE_Match object; span=(3, 8), match='a$ -\n'

'\w'匹配[A-Za-z0-9]

res = re.search("\w+","1dF23$- \r\na")
print(res)

执行输出:

_sre.SRE_Match object; span=(0, 5), match='1dF23'

'\W'匹配非[A-Za-z0-9]

res = re.search("\W+","1dF23$- \r\na")
print(res)

执行输出:

_sre.SRE_Match object; span=(5, 10), match='$- \r\n'

's'匹配空白字符、\t、\n、\r

res = re.search("\s+","1dF23$- \r\na")
print(res)

执行输出:

_sre.SRE_Match object; span=(7, 10), match=' \r\n'

'(?P<name>...)' 分组匹配 

组名为id,匹配数字

res = re.search("(?P<id>[0-9]+)","abcd1234daf@34")
#使用groupdict()方法打印组名
print(res.groupdict())

执行输出:

{'id': '1234'}

再添加一个分组name,匹配字母大小写

res = re.search("(?P<id>[0-9]+)(?P<name>[a-zA-Z]+)","abcd1234daf@34")
print(res.groupdict())

执行输出:

{'name': 'daf', 'id': '1234'}

返回的结果是一个字典,如果想取值的话,使用如下方法:

res = re.search("(?P<id>[0-9]+)(?P<name>[a-zA-Z]+)","abcd1234daf@34")
print(res.groupdict())
#第一种方法,直接传值
print(res.group("id"))
#第二种方法,用字典的方式
print(res.groupdict()['name'])

执行输出:

{'id': '1234', 'name': 'daf'}

1234

daf

举个复杂的例子

身份证号,前2位是省,再后面2位是市,再后面2位是区,再后面8位是出生日期

res = re.search("(?P<province>[0-9]{2})(?P<city>[0-9]{2})(?P<area>[0-9]{2})(?P<birthday>[0-9]{4})","371481199306143242").groupdict("city")
print(res)

执行输出:

{'birthday': '1993', 'city': '14', 'province': '37', 'area': '81'}

re.split 以匹配到的字符当做列表分隔符

res = re.split("[0-9]","abc12de3f45GH")
print(res)

执行输出:

['abc', 'de', 'f', 'GH']

re.sub   匹配字符并替换

res = re.sub("[0-9]+","|","abc12de3f45GH")
print(res)

执行输出:

abc|de|f|GH

只替换一个

res = re.sub("[0-9]+","|","abc12de3f45GH",count=1)
print(res)

执行输出:

abc|de3f45GH

仅需轻轻知道的几个匹配模式

re.I(re.IGNORECASE): 忽略大小写(括号内是完整写法,下同)
M(MULTILINE): 多行模式,改变'^'和'$'的行为(参见上面)
S(DOTALL): 点任意匹配模式,改变'.'的行为

忽略大小写

res = re.search("[a-z]+","abcA",flags=re.I)
print(res)

执行输出:

_sre.SRE_Match object; span=(0, 4), match='abcA'

res = re.search(r"^a","\nabc\neee",flags=re.M)
print(res)

执行输出:

_sre.SRE_Match object; span=(1, 2), match='a'

匹配任意字符

res = re.search(r".+","\nabc\neee",flags=re.S)
print(res)

执行输出:

_sre.SRE_Match object; span=(0, 8), match='\nabc\neee'

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Python疯子

数据分析之numpy

ndarray概述 创建n维数组 接收的是列表类型,所有元素类型必须相同 shape表示各维度大小的元组 dtype表示数组数据类型对象

15410
来自专栏老马说编程

(53) 剖析Collections - 算法 / 计算机程序的思维逻辑

之前几节介绍了各种具体容器类和抽象容器类,上节我们提到,Java中有一个类Collections,提供了很多针对容器接口的通用功能,这些功能都是以静态方法的方式...

23990
来自专栏用户画像

7.3.2 快速排序

快速排序是对冒泡排序的改进。其基本思想是基于分治法:在待排序L[1...n]中任取一个元素privot作为基准,通过一趟排序将待排序表划分为独立的两部分L[1....

6930
来自专栏mathor

波兰表达式

19940
来自专栏尾尾部落

普林斯顿大学算法公开课笔记——插入排序

现有一组数组 arr = [5, 6, 3, 1, 8, 7, 2, 4],共有八个记录,排序过程如下:

16210
来自专栏学海无涯

16.Swift学习之结构体

8720
来自专栏用户画像

7.2.1 直接插入排序

插入排序是一种简单直观的排序方法,其基本思想在于每次将一个待排序的记录,按其关键字大小插入到前面已经排好序的子序列,直到全部记录插入完成。

10020
来自专栏Java 源码分析

归并排序

归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。 首先考虑下如何将将二个有序数列...

27350
来自专栏大闲人柴毛毛

剑指offer——面试题10输入一个十进制整数,统计其中二进制1的个数

/** * 题目:输入一个十进制整数,统计其中二进制1的个数 * @author 大闲人柴毛毛 */ public class CountBitOne {...

38240
来自专栏云霄雨霁

子字符串查找----Boyer-Moore算法(从右向左匹配)

13500

扫码关注云+社区

领取腾讯云代金券