向前向后查找

import re

key = r'<html><body><h1>hello world<h1></body></html>'#这段是你要匹配的文本

#上面的一句也可以利用以下的实现,因为我们一般处理数据都是对文件进行操作的
#with open('/Users/Mr.Long/Desktop/data.txt', 'r') as f:
#   key = f.read()

p1 = r"(?<=<h1>).+?(?=<h1>)"#这是我们写的正则表达式规则,你现在可以不理解啥意思
pattern1 = re.compile(p1)#我们在编译这段正则表达式matcher1 = re.search(pattern1,key)#在源文本中搜索符合正则表达式的部分print (matcher1.group(0))



这其中的正则表达式就是

p1 = r"(?<=<h1>).+?(?=<h1>)"



其中?<=是向前匹配符,就该语句分析,你所要匹配的字符串必须以<h1>开头;同理,?=为向后匹配符,所匹配的语句必须以<h1>为结尾,否则在打印的那一条语句处会报错。

在此处顺便一提re.compile

这是面向对象用法:编译后多次操作

先使用compile()编译成正则表达式,之后再调用search、match、findall、split、sub、finditer方法。
没经过compile的字符串只是正则表达式的一种表现形式,经过compile后的才是正则表达式。
优点:一次编译可以多次使用该正则表达式进行匹配。

pat = compile(pattern,flags=0)



作用:

将一个正则表达式编译成一个正则表达式对象。


参数说明:
pattern:正则表达式字符串或原生字符串;
flags:正则表达式使用时的控制标记;


re库的match对象
re的search()、match()、finditer()返回的是一个match对象,search、match只返回匹配到的第一个字符串,需要返回全部匹配的字符串使用finditer,for循环全部打印出来。
match对象是:一次匹配的结果,它包含了很多匹配的相关信息。
match对象的属性
  
 •    .string   待匹配的的文本
    •    .re          匹配时使用的pattern对象(正则表达式)
    •    .pos       正则表达是搜索文本的开始位置
    •    .endpos  正则表达式搜索文本的结束位置


承接上面的代码:

matcher1.string
Out[52]: '<html><body><h1>hello world<h1></body></html>'

matcher1.re
Out[53]: re.compile(r'(?<=<h1>).+?(?=<h1>)', re.UNICODE)

matcher1.pos
Out[54]: 0

matcher1.endpos
Out[55]: 45


match对象的方法
    

•    .group(0)      获得匹配后的字符串

    •    .start()           匹配字符串在原字符串的开始位置

    •    .end()            匹配字符串在原字符串的结束位置

    •    .span()          返回(.start(),.end())元组结构

matcher1.start()
Out[57]: 16

matcher1.end()
Out[58]: 27

matcher1.span()
Out[59]: (16, 27)

matcher1.group(0)
Out[60]: 'hello world'



回溯引用

回溯引用是正则表达式内的一个“动态”的正则表达式,让你根据实际的情况变化进行匹配。

说白了,就是一个根据你的需要,动态变化的表达式。

举个栗子:

你原本要匹配<h1></h1>之间的内容,现在你知道HTML有多级标题,你想把每一级的标题内容都提取出来。你也许会这样写:



p = r"<h[1-6]>.*?</h[1-6]>"



这样一来,你就可以将HTML页面内所有的标题内容全部匹配出来。即<h1></h1>到<h6></h6>的内容都可以被提取出来。但是我们之前说过,写正则表达式困难的不是匹配到想要的内容,而是尽可能的不匹配到不想要的内容。在这个例子中,很有可能你就会被下面这样的用例玩坏。

比方说



<h1>hello world</h3>



发现后面的</h3>了吗?我们不管是怎么写出来这样的标题的,但实实在在的是我们的正则表达式同样会把这里面的hello world匹配出来。这时候就是回溯引用的重要作用。下面就是一个示例:

import re

key = r"<h1>hello world</h3>"
p1 = r"<h([1-6])>.*?</h\1>"
pattern1 = re.compile(p1)
m1 = re.search(pattern1,key)
print m1.group(0)#这里是会报错的,因为匹配不到,你如果将源字符串改成</h1>
#结尾就能看出效果



看到\1了吗?原本那个位置应该是[1-6],但是我们写的是\1,我们之前说过,转义符\干的活就是把特殊的字符转成一般的字符,把一般的字符转成特殊字符。普普通通的数字1被转移成什么了呢?在这里1表示第一个子表达式,也就是说,它是动态的,是随着前面第一个子表达式的匹配到的东西而变化的。比方说前面的子表达式内是[1-6],在实际字符串中找到了1,那么后面的\1就是1,如果前面的子表达式在实际字符串中找到了2,那么后面的\1就是2。

类似的,\2,\3,....就代表第二个第三个子表达式。

所以回溯引用是正则表达式内的一个“动态”的正则表达式,让你根据实际的情况变化进行匹配。