2019-08-13_Note_Day17

一、正则表达式

1. 什么是正则表达式

正则表达式是处理字符串的工具,通过不同的正则符号来描述字符串的规则

2. 正则符号(正则表达式的语法)

1) 普通字符(普通字符代表字符本身)

除了在正则中有特殊功能和特殊意义的符号以外的字符都是普通字符
# 匹配一个字符串有三个字符,分别是'a', 'b', 'c'
re_str = 'abc'
result = fullmatch(re_str, 'abc')
print(result)  # <_sre.SRE_Match object; span=(0, 3), match='abc'>

2) . 匹配任意一个字符, 一个.只能匹配一个字符

# 匹配一个字符串长度是8,前三个字符是abc,后三个字符是123,中间任意两个字符
re_str = r'abc..123'
result = fullmatch(re_str, 'abc-+123')
print(result)  # <_sre.SRE_Match object; span=(0, 8), match='abc-+123'>

3) \w 匹配一个数字、字母或者_(在ASCII码表中), 一个\w只能匹配一个字符

# 匹配一个长度是4的字符串,第一个字符是数字、字母或者_,后三个字符是abc
re_str = r'\wabc'
result = fullmatch(re_str, '_abc')
print(result)  # <_sre.SRE_Match object; span=(0, 4), match='_abc'>

4) \d 匹配任意一个数字字符, 一个\d只能匹配一个字符

# 匹配一个长度是5的字符串,前两个字符是任意数字,后面三个是任意字符
re_str = r'\d\d...'
result = fullmatch(re_str, '12sfa')
print(result)  # <_sre.SRE_Match object; span=(0, 5), match='12sfa'>

5) \s 匹配任意一个空白字符, 一个\s只能匹配一个字符

空白字符包括空格,换行符,制表符等
result = fullmatch(r'how\sare!', 'how are!')
print(result)  # <_sre.SRE_Match object; span=(0, 8), match='how are!'>

6) \大写字母

\D 匹配除了数字字符以外的任意字符(匹配一个非数字字符)
\S 匹配一个非空白字符
re_str = r'\Dabc\S'
print(fullmatch(re_str, '+abc1'))  # <_sre.SRE_Match object; span=(0, 5), match='+abc1'>

7) [字符集] 匹配字符集中出现的任意一个字符

注意:一个[]只能匹配一个字符
a.
[abc] 匹配abc中任意一个字符
# 匹配一个长度是4的字符串,第一个字符是1或3或7,后三个字符是abc
re_str = r'[137]abc'
print(fullmatch(re_str, '1abc'))  # <_sre.SRE_Match object; span=(0, 4), match='1abc'>
print(fullmatch(re_str, '2abc'))  # None
b.

[1-9] 匹配1~9中的任意一个字符(字符编码值递增)
[a-z] 匹配任意一个小写字母
[A-Z] 匹配任意一个大写字母
[a-zA-Z] 匹配任意一个字母
[a-zA-Z\d_] 匹配任意一个字母、数字或_
[ \t\n] 匹配任意一个空白字符
[\u4e00-\u9fa5] 匹配任意一个中文字符

re_str = r'[!-&]123'
print(fullmatch(re_str, '$123'))  # <_sre.SRE_Match object; span=(0, 4), match='$123'>
print(fullmatch(re_str, '(123'))  # None
re_str = r'[a-zA-Z\d_]==='
print(fullmatch(re_str, '1==='))  # <_sre.SRE_Match object; span=(0, 4), match='1==='>
print(fullmatch(re_str, 'W==='))  # <_sre.SRE_Match object; span=(0, 4), match='W==='>

# print(fullmatch(r'[z-a]', 'a'))  # sre_constants.error: bad character range z-a at position 1

8) [^字符集] 匹配不在字符集中的任意一个字符

[^abc] 匹配任意一个不是a,b,c的字符
[^2-8] 匹配任意一个不是数字2-8的字符
[^\u4e00-\u9fa5] 匹配任意一个非中文字符

re_str = r'[^2-8]abc'
print(fullmatch(re_str, '0abc'))  # <_sre.SRE_Match object; span=(0, 4), match='0abc'>
print(fullmatch(re_str, '5abc'))  # None

2. 检测符号

所有的检测符号都不会影响字符串的长度

1) \b :检查是否是单词边界

单词边界指的是能够将两个单词隔开并且不会产生歧义的任意符号(空白字符、标点符号、字符串开头和字符串结尾)
匹配规则: 先去掉\b对字符串进行匹配,如果匹配成功再检查\b所在的位置是否是单词边界
# 匹配一个长度为6的字符串,每个字符分别是a,b,c,1,2,3,并且要求abc和123之间是单词边界
re_str = r'abc\b123'
print(fullmatch(re_str, 'abc123'))  # None

re_str = r'abc\b,123'
print(fullmatch(re_str, 'abc,123'))  # <_sre.SRE_Match object; span=(0, 7), match='abc,123'>
print(search(r'\d\d', 'sf86sfs 67 =--'))  # <_sre.SRE_Match object; span=(2, 4), match='86'>
print(search(r'\b\d\d\b', 'sf86sfs 67 =--'))  # <_sre.SRE_Match object; span=(8, 10), match='67'>

2) ^ :检查^所在的位置是否是字符串开头

注意:这里的^要在[]外面
re_str = r'^\d\d\d'
print(fullmatch(re_str, '345'))  # <_sre.SRE_Match object; span=(0, 3), match='345'>
print(search(re_str, 'dasfa345sdh982==654=='))  # None
print(findall(re_str, '345sdh982==654=='))  # ['345']
print(search(r'^\d\d\d', '345'))  # <_sre.SRE_Match object; span=(0, 3), match='345'>

3) $ :检查$所在的位置是否是字符串结尾

re_str = r'\d\d\d$'
print(fullmatch(re_str, '345'))  # <_sre.SRE_Match object; span=(0, 3), match='345'>
print(search(re_str, 'dasfa345sdh982==654==124'))  # <_sre.SRE_Match object; span=(21, 24), match='124'>
print(findall(re_str, '345sdh982==654==123'))  # ['123']

3. 控制次数的符号

1) * 匹配0次或多次

123a* 123后面a出现0次或多次(123,123a,123aa)
123\d* 123后面出现0个或者多个任意数字字符(123,1230,12311)
123[mnxy9]* 123,123m,123mmn,12399

re_str = r'abc0*123'
print(fullmatch(re_str, 'abc00123'))  # <_sre.SRE_Match object; span=(0, 8), match='abc00123'>

2) + 匹配1次或多次

123a+ 匹配123a,123aa,123aaa...
re_str = r'123[a-z]+'
print(fullmatch(re_str, '123iyujh'))  # <_sre.SRE_Match object; span=(0, 8), match='123iyujh'>

3) ? 匹配0次或1次

-?123 匹配123/-123
re_str = r'_?abc'
print(fullmatch(re_str, 'abc'))  # <_sre.SRE_Match object; span=(0, 3), match='abc'>
print(fullmatch(re_str, '_abc'))  # <_sre.SRE_Match object; span=(0, 4), match='_abc'>

4) {}

{N} 匹配N次

a{3} 匹配3个a
\d{3} 匹配任意3个数字,345,344,000...

{M, N} 匹配M~N次(至少M次,至多N次)
{M,} 匹配至少M次
{, N} 匹配至多N次

# 匹配电话号码
re_str = r'1[3-9]\d{9}'
# 匹配密码,要求是6-12位的数字或者字母
re_str = r'[a-zA-Z\d]{6,12}'
print(fullmatch(r'123a{2,4}', '123aa'))  # <_sre.SRE_Match object; span=(0, 5), match='123aa'>
print(fullmatch(r'123a{2,4}', '123a'))  # None

5) 贪婪和非贪婪

在匹配次数不确定时,会出现贪婪和非贪婪两种情况:默认情况都是贪婪
贪婪:在能够匹配成功的情况下,匹配次数尽可能多
非贪婪:在能够匹配成功的情况下,匹配次数尽可能少(在匹配次数后加?)
re_str = r'a.+'
print(search(re_str, 'hsjsa==2-32'))  # <_sre.SRE_Match object; span=(4, 11), match='a==2-32'>
print(search(r'a.+?', 'hsjsa==2-32'))  # <_sre.SRE_Match object; span=(4, 6), match='a='>

re_str = r'a.+b'
print(search(re_str, 'a234b123b123'))  # <_sre.SRE_Match object; span=(0, 9), match='a234b123b'>
re_str = r'a.+?b'
print(search(re_str, 'a234b123b123'))  # <_sre.SRE_Match object; span=(0, 5), match='a234b'>

4. 分支和分组

1) | 分支

正则1|正则2 : 先让正则1匹配,如果匹配成功就成功,匹配失败再让正则2匹配(正则1和正则2中只要有一个能匹配成功即可)
re_str = r'abc|123'
print(fullmatch(re_str, 'abc'))  # <_sre.SRE_Match object; span=(0, 3), match='abc'>
print(fullmatch(re_str, '123'))  # <_sre.SRE_Match object; span=(0, 3), match='123'>

re_str = r'\d{2,5}|[a-z]+123'
print(fullmatch(re_str, '2141'))  # <_sre.SRE_Match object; span=(0, 4), match='2141'>
print(fullmatch(re_str, 'a123'))  # <_sre.SRE_Match object; span=(0, 4), match='a123'>
练习1:写一个正则表达式,要求匹配一个字符串:abc的前面是两个数字或者两个大写字母
# 方法1
re_str = r'\d{2}abc|[A-Z]{2}abc'
print(fullmatch(re_str, '41abc'))  # <_sre.SRE_Match object; span=(0, 5), match='41abc'>
print(fullmatch(re_str, 'QWabc'))  # <_sre.SRE_Match object; span=(0, 5), match='QWabc'>

2)()分组: 将()中的内容作为一个整体

a. 整体操作
r'(\d|[A-Z]){2}abc' : 匹配一个字符串,后面是abc,前面是两个数字或者两个大写字母
r'([a-zA-Z]\d){3}' : 字母数字重复3次
b. 分组
分组截取:方面后面分段或者分情况取不同的匹配结果
re_str = r'(\d{3})[a-z]{3}'
print(fullmatch(re_str, '344hsj'))  # <_sre.SRE_Match object; span=(0, 6), match='344hsj'>
print(findall(re_str, 'sdf345赛风weg568lkjoik==789wer--899fdsf'))  # ['568', '789', '899']
分组重复:在正则中用\X重复第X个分组匹配到的内容
re_str = r'(\d{3})[a-z]{3}\1'
print(fullmatch(re_str, '123abc123'))  # <_sre.SRE_Match object; span=(0, 9), match='123abc123'>
print(fullmatch(re_str, '123abc122'))  # None

re_str = r'(\d{3})([a-z]{3})\2'
print(fullmatch(re_str, '123abcsaf'))  # None
print(fullmatch(re_str, '123abcabc'))  # <_sre.SRE_Match object; span=(0, 9), match='123abcabc'>
注意:\X的前面必须有这个分组

5. 转义符号

1) 加\

在正则中有特殊功能和特殊意义的符号前加\,让这个符号的特殊功能和意义消失
re_str = r'\d{3}\.[a-z]{3}'
print(fullmatch(re_str, '111.abc'))  # <_sre.SRE_Match object; span=(0, 7), match='111.abc'>
print(fullmatch(re_str, '111=abc'))  # None

re_str = r'a\+\d{3}'
print(fullmatch(re_str, 'a+123'))  # <_sre.SRE_Match object; span=(0, 5), match='a+123'>
print(fullmatch(re_str, 'a0123'))  # None

2) 加[]

[]中有特殊意义的符号: a. ^放在最开头; b. -放在两个字符中间
其它符号包括:.,+,?,*,$这些单独的符号在[]中都表示这个符号本身
re_str = r'\d{3}[.][a-z]{3}'
print(fullmatch(re_str, '123.ada'))  # <_sre.SRE_Match object; span=(0, 7), match='123.ada'>
print(fullmatch(re_str, '123_ada'))  # None

二、re模块

re模块是python提供的,专门针对正则表达式应用的相关函数

1. compile(正则表达式) : 将正则表达式转换成正则对象

re_obj = compile(r'\d{3}')

fullmatch(r'\d{3}', '347')
re_obj.fullmatch('347')

2.字符串匹配

fullmatch(正则表达式, 字符串) : 让正则表达式和字符串完全匹配

match(正则表达式, 字符串) : 匹配字符串开头

以上两个方法的结果:匹配失败结果是None, 匹配成功会返回匹配对象

re_str = '\d{3}'
print(fullmatch(re_str, '783sdfs'))  # None
print(match(re_str, '783sdfs'))  # <_sre.SRE_Match object; span=(0, 3), match='783'>

1) 匹配对象

a. 获取匹配到的字符串
匹配对象.group() : 获取整个正则表达式匹配到的字符串,结果是字符串
匹配对象.group(N) : 获取整个正则表达式中第N个分组匹配到的字符串
result = fullmatch(r'(\d{3})=([a-z]{2})', '234=am')
print(result)  # <_sre.SRE_Match object; span=(0, 6), match='234=am'>
print(result.group())  # 234=am
print(result.group(1))  # 234
print(result.group(2))  # am
b. 获取匹配到的字符串在原字符串中的位置信息
匹配对象.span() : 返回匹配结果在原字符串中的下标范围[开始下标, 结束下标)
匹配对象.span(N) : 返回第N个分组的匹配结果在原字符串中的下标范围[开始下标, 结束下标)
print(result.span())  # (0, 6)
print(result.span(2))  # (4, 6)
c. 获取原字符串
匹配对象.string
print(result.string)  # 234=am

3. 查找

1)search(正则表达式, 字符串)

在字符串中查找第一个满足正则表达式的子串,如果找到结果是匹配对象,否则是None
result = search(r'\d{3}', '324ggs+++325hsdf')
print(result)  # <_sre.SRE_Match object; span=(0, 3), match='324'>

2)findall(正则表达式, 字符串)

获取字符串中所有满足正则表达式的子串;返回值是一个列表
result = findall(r'\d{3}[a-z]{2}', 's234hu赛跟随345mmkxv89h-=数348jl僧二维表')
print(result)  # ['234hu', '345mm', '348jl']
result = findall(r'(\d{3})[a-z]{2}', 's234hu赛跟随345mmkxv89h-=数348jl僧二维表')
print(result)  # ['234', '345', '348']
result = findall(r'(\d{3})([a-z]{2})', 's234hu赛跟随345mmkxv89h-=数348jl僧二维表')
print(result)  # [('234', 'hu'), ('345', 'mm'), ('348', 'jl')]
注意:如果正则表达式中有分组,列表中的匹配结果只会取分组匹配到的内容

3)finditer(正则表达式, 字符串)

获取字符串中所有满足正则表达式的子串;返回值是一个迭代器,元素是匹配对象
result = finditer(r'(\d{3})([a-z]{2})', 's234hu赛跟随345mmkxv89h-=数348jl僧二维表')
group = []
group1 = []
group2 = []
for x in result:
    group.append(x.group())
    group1.append(x.group(1))
    group2.append(x.group(2))
print(group, group1, group2)  # ['234hu', '345mm', '348jl'] ['234', '345', '348'] ['hu', 'mm', 'jl']

4. 切割

split(正则表达式, 字符串)

将字符串中满足正则表达式的子串作为切割点,对字符串进行切割;返回一个字符串列表
result = split(r'\d+', '多棱镜3ja89撒扥撒899SDS')
print(result)  # ['多棱镜', 'ja', '撒扥撒', 'SDS']

5. 替换

sub(正则表达式, 字符串1, 字符串2)

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

推荐阅读更多精彩内容