基础部分在这里:正则表达式(一)——基础之匹配字符,数量,边界
这部分我将换种形式来讲述,结合实际问题需求来讲述。
3.匹配分组
字符 | 功能 |
| | 匹配左右任意一个表达式 |
(ab) | 将括号中的字符作为一个分组 |
\num | 引用分组num匹配到的字符串 |
(?P<name>) | 分组起别名 |
(?P=name) | 引用别名为name分组匹配到的字符串 |
1)|
需求:匹配出0-100之间的数字
分析:首先我们明确这之间的数字包含0,两位数,100,,也就是一位,两位,三位的可能都有,鉴于一位0,三位100都是单独数字,我们可以使用 | 来连接(相当于or),着重考虑一位数[1-9],两位数[10-99],分析其特征,这里第一位数必须为[1-9],第二位[0-9]都可以(\d可以表示),对于一位数[1-9]的第二位可以不出现(?可以表示),再加个结尾$,防止234匹配到23的情况。因此正则表达式为:
r'[1-9]\d?$|0$|100$'
>>> re.match(r'[1-9]\d?$|0$|100$','08') None >>> re.match(r'[1-9]\d?$|0$|100$','0') <_sre.SRE_Match object; span=(0, 1), match='0'> >>> re.match(r'[1-9]\d?$|0$|100$','100') <_sre.SRE_Match object; span=(0, 3), match='100'> >>> re.match(r'[1-9]\d?$|0$|100$','101') None >>> re.match(r'[1-9]\d?$|0$|100$','80') <_sre.SRE_Match object; span=(0, 2), match='80'>
我们再看下0能不能不用 | ,也把它包含进去?答案of course。想想 0 ,它是[1-9]不出现,第二位\d也不出现的情况,因此第一位[1-9]选择性出现用 ? ,因此正则表达式为:
r'[1-9]?\d?$|100$'
>>> re.match(r'[1-9]?\d?$|100$','0') <_sre.SRE_Match object; span=(0, 1), match='0'>
这样的话,| 的功能是不是清楚了......
2)(ab) 将括号中的字符作为一个分组
需求 :在网页开发或者爬虫时,处理对象是HTML,比如某网页HTML中有这样的内容:<h1>我的CSDN</h1>。那么我该如何把<h1>content</h1>中的content提取出来呢?
分析:提取的内容用()括起来就可以了。<h1> </h1>是固定标签,这是不变的,变的是content,因此我的正则表达式可表示为:
r'<h1>(.*)</h1>'
>>> re.match(r'<h1>(.*)</h1>','<h1>我的CSDN</h1>') <_sre.SRE_Match object; span=(0, 15), match='<h1>我的CSDN</h1>'>
可以完美的匹配到了,问题还没解决,我怎么提取出来content呢。其实group()函数是可以接受参数的,其参数的意义是你的()个数的索引,比如你输入reslut.group(1)得到的是第一个括号的内容。reslut.group(0)是匹配到的所有内容,默认为0,所以你不输入,默认为0,返回匹配内容。Match Object还有个groups()函数,它返回的是所有括号的内容。如下所示:
>>> result = re.match(r'<h1>(.*)</h1>','<h1>我的CSDN</h1>') #变量保存 >>> result.group() #默认0,返回匹配内容 '<h1>我的CSDN</h1>' >>> result.group(0) #输入0,返回匹配内容 '<h1>我的CSDN</h1>' >>> result.group(1) #返回第1个括号内容 '我的CSDN' >>> result.groups() ('我的CSDN',)
我们看看两个括号的情况:
>>> result = re.match(r'<span>(\d+)</span><h1>(.*)</h1>','<span>1234</span><h1>我的CSDN</h1>') >>> result <_sre.SRE_Match object; span=(0, 32), match='<span>1234</span><h1>我的CSDN</h1>'> >>> result.group(1) '1234' >>> result.group(2) '我的CSDN' >>> result.groups() ('1234', '我的CSDN')
所以说,()在网页开发,爬虫里还是挺重要的......学会它
3)\num 引用分组num匹配到的字符串
需求 :还是以网页为例,比如判断某网页HTML格式是否正确,其中有内容:<html><h1>我的CSDN</h1></html>。这时,我们不关心里面的内容,我们关心的是格式是否正确,就是说这样的格式:<html>标签必须有</html>结束,<h1>标签必须有</h1>结束。
分析:这个时候像html和h1才是关键内容,如果我们把这些用()保存起来,并且在后面一定对应这些内容,就能保证标签的配对,而\num就是解决这样的问题的,上面group里面的参数index指的是第index个括号内容,\index即取得它的内容
1. 首先我们看个错误的样例:
>>> s = '<html><h1>my csdn</h1></html>' >>> re.match(r'<.+><.+>.+</.+></.+>',s) #关注html和h1这些内容, .+ 表示至少有内容 <_sre.SRE_Match object; span=(0, 29), match='<html><h1>my csdn</h1></html>'> >>> s = '<html><h1>my csdn</h1></h>' '''把s后面的html改成h,明显格式不对,但还是匹配了''' >>> re.match(r'<.+><.+>.+</.+></.+>',s) <_sre.SRE_Match object; span=(0, 26), match='<html><h1>my csdn</h1></h>'>
我们应该让第一个<tag>的内容出现在最后</tag>中,因此需要保存起来,用()括起来
2.正确的方法
我们应该把<tag>用()括起来,变成<(tag)>,因此正则表达式为:
r'<(.+)><(.+)>.+</\2></\1>'
解释下,这个\2 和 \1。这个就是我们上面groups()中的内容索引,可以拿到内容
>>> s = '<html><h1>my csdn</h1></h>' #错误的标签格式 >>> re.match(r'<(.+)><(.+)>.+</\2></\1>',s) #此时不符合了 None >>> s = '<html><h1>my csdn</h1></html>' #正确的标签格式 >>> result = re.match(r'<(.+)><(.+)>.+</\2></\1>',s) >>> result <_sre.SRE_Match object; span=(0, 29), match='<html><h1>my csdn</h1></html>'> >>> result.groups() #那么 \2 指的是'h1' ; \1 指的是'html' ('html', 'h1')
s = '<html><h1>my csdn</h1></html>
result = re.match(r'<(?P<k1>.+)><(?P<k2>.+)>.+</(?P=k2)></(?P=k1)>',s)
>>> result
<_sre.SRE_Match object; span=(0, 29), match='<html><h1>my csdn</h1></html>