Python之re模块

一、正则表达式

re模块是python独有的匹配字符串的模块,该模块中提供的很多功能是基于正则表达式实现的,
而正则表达式是对字符串进行模糊匹配,提取自己需要的字符串部分,他对所有的语言都通用。

  • re模块是python独有的
  • 正则表达式所有编程语言都可以使用
  • re模块、正则表达式是对字符串进行操作
(一)常用正则

1、字符

元字符 匹配内容
. 匹配除换行符以外的任意字符
\n 匹配一个换行符
\t 匹配一个制表符
^ 匹配字符串的开始
$ 匹配字符串的结尾
a|b 匹配字符a或字符b
[...] 匹配字符组中的字符
[^...] 匹配除了字符组中字符的所有字符
() 匹配括号内的表达式,也表示一个组
(?:表达式) 取消括号的分组功能

2、字符集

正则 说明
\d 匹配数字,它相当于类[0-9]
\D 匹配非数字,它相当于类[^0-9]
\s 匹配任意的空白符,它相当于类[\t\n\r\f\v]
\S 匹配非空白符,它相当于类[^\t\n\r\f\v]
\w 匹配字母或数字或下划线,它相当于类[a-zA-Z0-9_]
\W 匹配非字母或数字或下划线,它相当于类[^a-zA-Z0-9_]
\b 匹配位于开始或结尾的空字符串
\B 匹配不位于开始或结尾的空字符串,它相当于类[^\b]
\A 仅匹配字符串开头,同^
\Z 仅匹配字符串结尾,同$

3、量词
贪婪模式:总是尝试匹配尽可能多的字符
非贪婪则相反,总是尝试匹配尽可能少的字符。

量词 用法说明
* 重复零次或更多次
+ 重复一次或更多次
? 重复零次或一次
{n} 重复n次
{n,} 重复n次至无限次
{n,m} 重复n到m次

{0,}匹配前一个字符0或多次,等同于*元字符
{+,}匹配前一个字符1次或无限次,等同于+元字符
{0,1}匹配前一个字符0次或1次,等同于?元字符
如果()后面跟的是特殊元字符如 (adc)* 那么*控制的前导字符就是()里的整体内容,不再是前导一个字符

4、特殊分组用法表:只对正则函数返回对象的有用

用法 用法说明
(?P<name>) 分组起别名,?P<>定义组里匹配内容的key(键),<>里面写key名称,值就是匹配到的内容,用groupdict()打印字符串
(?P=name) 引用别名为<name>的分组匹配到字符串
\num 引用编号为num的分组匹配到字符串,第0组是整体
import re
#匹配出“<html><h1>[www.it123.com](http://www.it123.com/)</h1></html>”
ret = re.search(r"<(?P<name1>\w*)><(?P<name2>\w*)>.*</(?P=name2)></(?P=name1)>", "<html><h1>www.it123.com</h1></html>")
print(ret.group())
#<html><h1>www.it123.com</h1></html>
#先给两个分组起了别名name1、name2,后边引用这两个别名,所以值要对应起来
ret = re.search(r"<(?P<name1>\w*)><(?P<name2>\w*)>.*</(?P=name2)></(?P=name1)>", "<html><h1>www.it123.com</h2></html>")
print(ret.group())
#报错‘NoneType’,因为h1和h2不对应

a1='21abc11abc2'
a2= re.search(r"(\d)(\d)abc\2", a)
print(a2.group())
#21abc1
#\2表示前边第二个分组

b1='21abc11abcabc2'
b2 = re.search(r"(?P<id>abc){2}", a)
print(b2 .group())
#abcabc

5、断言
从断言的表达形式可以看出,它用的就是分组符号,只不过开头都加了一个问号,这个问号就是在说这是一个非捕获组,这个组没有编号,不能用来后向引用,只能当做断言。

用法 用法说明
(?=X) 正先行断言。仅当子表达式 X 在 此位置的右侧匹配时才继续匹配。例如,/w+(?=/d) 与后跟数字的单词匹配,而不与该数字匹配。此构造不会回溯。
(?!X) 负先行断X言。仅当子表达式 X 不在 此位置的右侧匹配时才继续匹配。例如,例如,/w+(?!/d) 与后不跟数字的单词匹配,而不与该数字匹配 。
(?<=X) 正后发断言。仅当子表达式 X 在 此位置的左侧匹配时才继续匹配。例如,(?<=19)99 与跟在 19 后面的 99 的实例匹配。此构造不会回溯。
(?<!X) 负后发断言。仅当子表达式 X 不在此位置的左侧匹配时才继续匹配。例如,(?<!19)99 与不跟在 19 后面的 99 的实例匹配

匹配<title>xxx</title>xxx(?<=<title>).*(?=</title>)
自己理解就是:

  1. 前两种断言要放在xxx的后边写:
    (1.1)(?=X): 表示xxx后边有X
    (1.2)(?!X):表示xxx后边没有X
  2. 后两种断言要放在xxx的前边写:
    (2.1)(?<=X):表示xxx前边有X
    (2.2)(?<!X):表示xxx前边没有X

5、例子
(1)非
^(?!.*200).*$,只匹配200
^(?!.*[200|400]).*$,只匹配200和400
[^a-z]反取,不含a-z字母的
(2)\u4e00-\u9fa5 中文
(3)r"\b([\u4e00-\u9fa5]\s?[\u4e00-\u9fa5]+)\b" # 小 明 匹配这种单字中间有空格的


二、re模块

(一)原始字符 r的含义
  • 将在python里有特殊意义的字符如\b、\r,转换成原生字符
  • 就是去除它在python的特殊意义,字符串里是啥就是啥,不会改变
a="\\hello\b\r"
b=r"\\hello\b\r"
print(a)
print(b)
# \hello
#\\hello\b\r
(二)正则匹配模式表
修饰符 描述
re.I(re.IGNORECASE) 使匹配对大小写不敏感
re.L(re.LOCALE) 做本地化识别(locale-aware)匹配
re.M(re.MULTILINE) 多行匹配,影响 ^ 和 $
re.S(re.DOTALL) 使 . 匹配包括换行在内的所有字符
re.U 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B.
re.X 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。
(三)函数
1、re.compile(pattern[, flags])

compile 函数用于编译正则表达式,生成一个正则表达式( Pattern )对象,供 match() 和 search() 这两个函数使用

  • pattern : 一个字符串形式的正则表达式
  • flags :可选,表示匹配模式,比如忽略大小写,多行模式等具体为:re.I、re.L 、re.M 、re.S 、re.U 、re.X
2、re.match(pattern, string, flags=0)

match 尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,返回none。

  • pattern:匹配的正则表达式
  • string:要匹配的字符串。
  • flags : 可选,表示匹配模式
3、re.search(pattern, string, flags=0)

search 扫描整个字符串并返回第一个成功的匹配。

  • pattern :匹配的正则表达式
  • string:要匹配的字符串。
  • flags : 可选,表示匹配模式

re.match与re.search的区别:

  • re.match只匹配字符串的开始位置,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;
  • re.search匹配整个字符串,直到找到一个匹配。
4、 re.sub(pattern, repl, string, count=0, flags=0)

正则表达式替换函数

  • pattern:匹配的正则表达式
  • repl:需要替换成的字符串或函数
  • string:需要被替换的字符串
  • count:替换次数
  • flags:匹配模式
  • 特殊用法:\数字\g<数字>表示前面pattern里面第数字个分组,需要和r'\数字'联用,否则不好用,\g<0>,\0代表前面pattern匹配到的所有字符串。
import re
text="2020年10月14日"
text=re.sub(r"[\u4e00-\u9fa5]","-",text,2).strip("日")
#2020-10-14

c= 'abc124hello46goodbye67shit'
c=re.sub(r'\d+[hg]', 'foo1', c)
# abcfoo1ellofoo1oodbye67shit

a1 = re.sub('(\d{2})-(\d{2})-(\d{4})', r'\3-\1-\2', '06-07-2018')
a2 = re.sub('(\d{2})-(\d{2})-(\d{4})', r'\g<3>-\g<2>-\g<1>', '06-07-2018')
a3 = re.sub(r'(\d{4})(\d{2})(\d{2})', r'\1-\2-\3', '20201010')
#a1=2018-06-07
#a2=2018-06-07
#a3=2020-10-10
def replace_num(str):
    numDict = {
        "0": "〇",
        "1": "一",
        "2": "二",
        "3": "三",
        "4": "四",
        "5": "五",
        "6": "六",
        "7": "七",
        "8": "八",
        "9": "九",
    }
    #要用.group()取文本,因为是匹配出来的是对象
    print(str.group())
    return numDict[str.group()]
my_str = "2018年6月7号"
a = re.sub(r"(\d)", replace_num, my_str)
print(a)  
# 二〇一八年六月七号,每次匹配一个数字,执行函数,获取替换后的值
#匹配多行
def process(text):
    import re
    if "|STCNTTTP|" in text:
        text=re.sub("\|STCNTTTP\|.*option.*\|STCNTTTP\|","",text,flags=re.DOTALL)
    return text
4.1、subn(pattern, repl, string, count=0, flags=0)

替换匹配成功的指定位置字符串,并且返回替换次数,可以用两个变量分别接受

  • pattern: 正则模型
  • repl : 要替换的字符串
  • string : 要匹配的字符串
  • count : 指定匹配个数
  • flags : 匹配模式
import re
origin = "hello alex bcd alex lge alex acd 19"
a,b = re.subn("a","替换",origin) 
print(a)
print(b)
#hello 替换lex bcd 替换lex lge 替换lex 替换cd 19
#4
5、re.split(pattern, string, maxsplit=0)
  • 多个 分隔符,切割功能非常强大
  • 通过正则表达式将字符串分离。
  • 如果用括号将正则表达式括起来,那么匹配的字符串也会被列入到list中返回。
  • maxsplit是分离的次数,maxsplit=1分离一次,默认为0,不限制次数。
    (1) 单字符切割:
re.split(';',line)
['aa bb cc dd', ' ee ff. gg- hh ii kk']

(2) 两个字符以上切割,放在 [ ]中(不保留分隔符):

re.split('[;.-]',line)
['aa bb cc dd', ' ee ff', ' gg', ' hh ii kk']

(3) 使用( )捕获分组(保留分割符):

re.split('([;,])',line)
['aa bb cc dd', ';', ' ee ff', '.', ' gg', '-', ' hh ii kk']
def process(text):
    """
    eg:安徽省住房和城乡建设厅党组书记、厅长  赵馨群
    eg:省工商局局长 朱斌  省商务厅副厅长 乔兴力
    空格分割,多个的,长多于3的不要
    """
    import re
    res=text.split()
    print(res)
    if len(res)>1:
        return [i.replace(" ", "") for i in res if 1 < len(i) < 4]
    if len(res)==1:
        return [i.replace(" ", "") for i in res]
    else:
        return text
6、findall(string[, pos[, endpos]])

在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。
注意: match 和 search 是匹配一次 ,findall 匹配所有。

  • string : 待匹配的字符串。
  • pos : 可选参数,指定字符串的起始位置,默认为 0。
  • endpos : 可选参数,指定字符串的结束位置,默认为字符串的长度。

用法:

  • 1、无分组:匹配所有合规则的字符串,匹配到的字符串放到一个列表中
  • 2、有分组:只将匹配到的字符串里,组的部分放到列表里返回(相当于groups()方法)
  • 3、多个分组:只将匹配到的字符串里,组的部分放到一个元组中,最后将所有元组放到一个列表里返(相当于在group()结果里再将组的部分,分别,拿出来放入一个元组,最后将所有元组放入一个列表返回)
  • 4、分组中有分组:只将匹配到的字符串里,组的部分放到一个元组中,先将包含有组的组,看作一个整体也就是一个组,把这个整体组放入一个元组里,然后在把组里的组放入一个元组,最后将所有组放入一个列表返回(只要是个组就把结果放元组里,有几个组,元组里就有几个)
  • 5、?: 在有分组的情况下findall()函数,不只拿分组里的字符串,拿所有匹配到的字符串,注意?:只用于不是返回正则对象的函数如findall()
import re
#1无分组
origin = "hello alex bcd alex lge alex acd 19"
r = re.findall("a\w+", origin)
print(r)
#输出结果
#['alex', 'alex', 'alex', 'acd']

#2有分组
r = re.findall("a(\w+)", origin)    
print(r)
#输出结果
#['lex', 'lex', 'lex', 'cd']

#3多个分组
r = re.findall("(a)(\w+)", origin)
print(r)
#输出结果
#[('a', 'lex'), ('a', 'lex'), ('a', 'lex'), ('a', 'cd')]

#4分组中有分组
r = re.findall("(a)(\w+(e))", origin)    
print(r)
#输出结果
#[('a', 'le', 'e'), ('a', 'le', 'e'), ('a', 'le', 'e')]

#5?:
b = re.findall("a(?:\w+)",origin) 
print(b)
#输出
# ['alex', 'alex', 'alex', 'acd']

#findall匹配多个值,取值
def process(text):
    import re
    l=re.findall(r"javascript:download\('\./(.*?\.pdf)','(.*?\.pdf)'\);",text)
    ptf_l=list(l[0])
    url=f"https://www.shclearing.com/wcm/shch/pages/client/download/download.jsp?FileName={ptf_l[0]}&DownName={ptf_l[1]}"
    print(url)
process("javascript:download('./P020200729557188212660.pdf','漳州市九龙江集团有限公司关于主体信用评级发生变化的公告.pdf');")
#获取到的l是元组的格式

注意1:一旦匹配成,再次匹配,是从前一次匹配成功的,后面一位开始的,也可以理解为匹配成功的字符串,不在参与下次匹配

import re
#无分组
r = re.findall("\d+\w\d+", "a2b3c4d5")    #浏览全部字符串,匹配所有合规则的字符串,匹配到的字符串放到一个列表中
print(r)
#输出结果
#['2b3', '4d5']
#注意:匹配成功的字符串,不在参与下次匹配,所以3c4也符合规则但是没匹配到

注意2:如果没写匹配规则,也就是空规则,返回的是一个比原始字符串多一位的,空字符串列表

import re
#无分组
r = re.findall("", "a2b3c4d5")    #浏览全部字符串,匹配所有合规则的字符串,匹配到的字符串放到一个列表中
print(r)
#输出结果
#['', '', '', '', '', '', '', '', '']
#注意:如果没写匹配规则,也就是空规则,返回的是一个比原始字符串多一位的,空字符串列表 

注意3:正则匹配到空字符的情况,如果规则里只有一个组,而组后面是*就表示组里的内容可以是0个或者多过,这样组里就有了两个意思:
一个意思是匹配组里的内容,
二个意思是匹配组里0内容(即是空白)
所以尽量避免用*否则会有可能匹配出空字符串

import re
origin = "hello alex bcd alex"
r = re.findall("(a)*", origin)   
print(r)
#['', '', '', '', '', '', 'a', '', '', '', '', '', '', '', '', 'a', '', '', '', '']
7、方法

正则表达式,返回类型为表达式对象的
如:<_sre.SRE_Match object; span=(6, 7), match='a'>
返回对象的,需要用正则方法取字符串,

  • group():group() 同group(0)就是匹配正则表达式整体结果,不管有没有分组将匹配到的全部拿出来
  • group(num>0):返回匹配到的对应第num个分组结果
  • groups() :返回所有分组匹配的列表 =(group(1),group(2).....)
  • groupdict() :只返回分组中定义了key的组的结果
  • start() :返回匹配开始的位置
  • end() :返回匹配结束的位置
  • span() :返回一个元组包含匹配 (开始,结束) 的位置
import re
#无分组
origin = "hello alex bcd alex lge alex acd 19"
r = re.search("a\w+", origin)   
r1 = re.search("a(\w+).*(\d)", origin) 
r2 = re.search("a(?P<n1>\w+).*(?P<n2>\d)", origin)
# group获取匹配到的所有结果,不管有没有分组将匹配到的全部拿出来
print(r.group())     
print(r1.group())   
print(r1.group(2))  
print(r2.group()) 
 # groups获取模型中匹配到的分组结果,只拿出匹配到的字符串中分组部分的结果
print(r.groups())   
print(r1.groups())    
print(r2.groups())   
# 获取模型中匹配到的分组结果,只拿出匹配到的字符串中分组部分定义了key的组结果
print(r.groupdict()) 
print(r1.groupdict()) 
print(r2.groupdict()) 
r3 = re.search("(h).*a(?P<n1>\w+).*(?P<n2>\d)", origin)
print(r3.groupdict()) 
#alex
#alex bcd alex lge alex acd 19
#9
#alex bcd alex lge alex acd 19

#()
#('lex', '9')
#('lex', '9')

#{}
#{}
#{'n1': 'lex', 'n2': '9'}
#{'n1': 'cd', 'n2': '9'}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,142评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,298评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,068评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,081评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,099评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,071评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,990评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,832评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,274评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,488评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,649评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,378评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,979评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,625评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,643评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,545评论 2 352

推荐阅读更多精彩内容

  • 不必羡慕那些活的精彩快乐的人,他们其实并不比你优秀,他们只是减轻了对他人高度的感受性;从而活在自己的节奏里面; 也...
    BeautifulSoulpy阅读 467评论 0 0
  • 以下示例所使用 python 版本为: 3.7 python 提供 re 模块,来满足正则表达式的使用。在开始介绍...
    zhipingChen阅读 1,846评论 0 3
  • 01. 正则表达式基础知识 1.1 原子 原子是正则表达式中最基本的组成单位,每个正则表达式中至少要包含一个原子,...
    莫忘初心_倒霉熊阅读 572评论 0 3
  • 什么是正则表达式 ​ 一组特殊符号组成的表达式,用于描述某种规则。该应用场景生活中随处可见。 ​ 例如:让...
    徐弱西阅读 2,144评论 0 1
  • 前面已经初步介绍了正则式的语法规则和re模块的方法。这次主要举了几个例子,看看re模块在实际工作中的使用。 1. ...
    0893051f5f11阅读 16,409评论 0 8