04.编程学习--正则表达式(入门二)

文:郑元春

人生苦短,我用Python!

接上篇《编程学习--正则表达式(入门一)》,今天把剩下的基础部分完成,然后开始讲解Python的re模块,有时间的话就讲解下这个模块的源码。分析源码会让理解更加的透彻

5.逻辑和分组

经过这两天的学习和写码测试,终于明白了分组和《入门一》讲的正则表达式不同了。前面讲的正则表达式都是全匹配的,结果会把所有的符合情况的字符串全部返回(输出),但是分组的话,他只会输出符合分组模式的字符串,组外的字符串(如果有的话)只是用来做匹配辅助的。

刚开始一直在纠结为啥组外的字符串没有输出来,今天突然想通了,Python的分组就是为了过滤符合分组模式的字符串的,所以Python的分组模式虽然是将整个的模式匹配了一遍,但是最后只会输出分组内的内容,在文中我会告诉你们怎么输出所有的匹配字符串。(那个在线的正则匹配验证的网站中还是会输出辅助字符的)。

  • 5.1|
    这个就是‘或’功能了,很简单不解释。|的优先级比较低,所以 ab|cd能够匹配的模式是ab或者是cd.如果|是在分组内的话,那么分组就会改变他的优先级,它的范围就只能在分组内了。
#case 1: 没有分组
reStr="ab|cd"
targetStr="ab cd abcd abc acd"
re.findall(reStr,targetStr)
>>>['ab','cd','ab','cd','ab','cd']
#case 2:使用分组(下部分讲分组)
reStr="a(b|c)d"
targetStr="ab cd abcd abc acd"
re.findall(reStr,targetStr)
>>>['c']
#先看下分组
result=re.search(reStr,targetStr)  #注意这里使用的是search函数,不是finall函数
result.groups()
>>>('c',)
result.span()
>>>(15, 18)
result.group(1)
>>>'c'

具体的分组下面会讲解,可以看到,虽然输出的仅仅是组内的匹配内容,但是通过span()还是可以看到其实是匹配了整个的acd的。

  • 5.2()

括号括起来的表达式将作为分组.为什么要引入分组呢,主要的原因还是在数量词的组合运用上。

有的时候模式后面会跟着数量词,而数量词只是匹配前一个字符,也就是现在只能重复单个字符,如果我们重复一个字符串怎么办呢,使用()分组可以将多个字符组合成一个字符串,之后就可以指定这个字符串的重复规则了。

比如 (ab){2,3}就表示的是abab或者是ababab。分组是可以嵌套使用的,将正则表达式从左边到右边扫描,每个分组就是找到的左括号(的顺序,以为后面还有使用分组索引、分组别名来替换分组的使用方法,这里只是顺便一提。

在这里先说下re模块中的两个函数:group和groups。具体的使用将会在re模块那一章节里面进行讲解。这里只是为了下面需要使用才进行简单的说明。

group和groups是两个不同的函数。

分组与不分组的情况区别是一个带着括号,另一个不带着括号,有的时候我们需要的是返回的字符串只匹配分组内的规则,有的时候我们需要返回的字符串是匹配整个正则表达式的规则,这两种需求都可以使用re.search()re.match()函数测试。两种函数都会返回一个matchobject对象,这个对象里面有如下的属性或者是方法:

属性:

  1. string:

匹配时使用的文本。

  1. re:

匹配时使用的Pattern对象。

  1. pos:

文本中正则表达式开始搜索的索引。值与Pattern.match()和Pattern.seach()方法的同名参数相同。

  1. endpos:

文本中正则表达式结束搜索的索引。值与Pattern.match()和Pattern.seach()方法的同名参数相同。

  1. lastindex:

最后一个被捕获的分组在文本中的索引。如果没有被捕获的分组,将为None。

  1. lastgroup:

最后一个被捕获的分组的别名。如果这个分组没有别名或者没有被捕获的分组,将为None。

方法:

  1. group([group1, …]):

获得一个或多个分组截获的字符串;指定多个参数时将以元组形式返回。group1可以使用编号也可以使用别名;编号0代表整个匹配的子串;不填写参数时,返回group(0);没有截获字符串的组返回None;截获了多次的组返回最后一次截获的子串。

  1. groups([default]):

以元组形式返回全部分组截获的字符串。相当于调用group(1,2,…last)。default表示没有截获字符串的组以这个值替代,默认为None。

  1. groupdict([default]):

返回以有别名的组的别名为键、以该组截获的子串为值的字典,没有别名的组不包含在内。default含义同上。

  1. start([group]):

返回指定的组截获的子串在string中的起始索引(子串第一个字符的索引)。group默认值为0。

  1. end([group]):

返回指定的组截获的子串在string中的结束索引(子串最后一个字符的索引+1)。group默认值为0。

  1. span([group]):

返回(start(group), end(group))。

  1. expand(template):

将匹配到的分组代入template中然后返回。template中可以使用\id或\g<id>、\g<name>引用分组,但不能使用编号0。\id与\g<id>是等价的;但\10将被认为是第10个分组,如果你想表达\1之后是字符'0',只能使用\g<1>0。

由于我们的分组是可以嵌套使用的,所以每个分组从左到右的索引就是扫描顺序,通过group(n)的方式来访问匹配的分组的字符。

而group() == group(0) == 所有匹配的字符,与括号无关,这个是API规定的。

所以带有分组的会返回两种格式,一种是和不带分组()一样,返回的是匹配整个正则表达式的字符串,一种是只返回分组内的字符串。下面用代码说话。

#case 1:最简单的分组
reStr="a(bc)"
targetStr="abcabc"
# 使用findall方式
re.findall(reStr,targetStr)
>>>['bc', 'bc'] #返回所有的匹配到的组内字符串
# 使用search方式
result=re.search(reStr,targetStr)
result.group()
>>>'abc'  #分组外的字符a也输出了
result.group(0)
>>>'abc'
result.group(1)
>>>'bc'  #只输出分组中匹配的内容
result.groups()
>>>('bc',) #输出的是tuple
#case 2:分组索引
reStr="a(bc)(de)"
targetStr="abcde bc de"
re.findall(reStr,targetStr)
>>>[('bc', 'de')]

result=re.search(reStr,targetStr)
result.group()
>>>'abcde'
result.group(0)
>>>'abcde'
result.group(1)
>>>'bc'
result.group(2)
>>>'de'
result.groups()
>>>('bc', 'de')
result.group(3)
>>>IndexError: no such group
result.group

通过case 1和case 2的比较就可以明白分组的索引是怎么回事了吧。同时也能够明白group()``group(0)以及group(n)还有groups()的关系了吧。

#case 3:分组嵌套
reStr="a(b(cd))"
targetStr="cd bcd abcd"
re.findall(reStr,targetStr)
>>>[('bcd', 'cd')]

result=re.search(reStr,targetStr)
result.group()
>>>'abcd'
result.group(0)
>>>'abcd'
result.group(1)
>>>'bcd'
result.group(2)
>>>'cd'
result.groups()
>>>('bcd', 'cd')
#case 4: 与数量模式并用
reStr="(abc){1,2}"
targetStr="abcabc"
re.findall(reStr,targetStr)
>>>['abc']

result=re.search(reStr,targetStr)
result.group()
>>>'abcabc'
result.group(0)
>>>'abcabc'
result.group(1)
>>>'abc'
result.groups()
>>>('abc',)
#case 5:与`|`的联合使用
reStr="(ab|cd)"
targetStr="abcd"
result=re.search(reStr,targetStr)
result.group()
>>>'ab'
result.group(1)
>>>'ab'
result.groups()
>>>('ab',)
  • 5.3(\\<number>)
    分组的时候,每一对括号代表着一个分组,从左边到右边依次编号为1,2,3......。match或者是search函数返回的是有group信息,通过访问group(1),group(2)可以直接取得分组索引为1,2的分组。
reStr=r"(ab)(cd)\\1"  #注意前面的r,以后还是全部带r吧
targetStr="abcdab"
re.findall(reStr,targetStr)
>>>[('ab', 'cd')]
result=re.search(reStr,targetStr)
result.group()
>>>'ababab'
result.group(1)
>>>'ab'
#如果将正则模式换成
reStr=r"(ab)(cd)\\1\\2"
targetStr="abcdabcd"
result=re.search(reStr,targetStr)
result.group()
>>>'abcdabcd'
result.group(1)
>>>'ab'
result.group(2)
>>>'cd'

注意:使用index的时候一定要在前面先写好分组模式,后面才能引用

  • 5.4(?P<name>)
    上面说的时候有没有点匿名函数的意思啊,其实还可以使用命名的方式来引用前面的分组信息。
reStr=r"(?P<g1>ab)(?P=g1)"
targetStr="abab"
result=re.search(reStr,targetStr)
result.group()
>>>'abab'
result.group(1)
>>>'ab'
result.groupdict()
>>>{'g1': 'ab'}
result.group('g1')
>>>'ab'

当使用name的时候就可以使用group(name)的方式来访问了

reStr=r"(?P<g1>ab)c(?P<g2>de)(?P=g1)(?P=g2)"
targetStr="abcdeabde"
result=re.search(reStr,targetStr)
result.group()
>>>'abcdeabde'
  • 5.5(?P=name)
    上面在5.4中已经说明了name的使用方法了。

总结

分组还是比较好的一个功能的,做过Django项目的同学一定在url配置的时候使用过正则表达式,所以url在Django叫做url pattern

同时需要注意group()和group(n)以及groups()的用法!另外,可以使用name来标识分组也是很人性化的。

参考

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

推荐阅读更多精彩内容