编程语言
首页 > 编程语言> > python正则表达式re库详解

python正则表达式re库详解

作者:互联网

re库详解

我们已经了解到正则表达式是处理字符串的强大工具,具有自己的语法结构,有了它,能实现字符串的检索、替换、匹配验证码等。
当然本文着重讲它在爬虫方向的用法,从html中提取信息。正则表达式虽然看起来一团糟,其实它也有自己的语法规范特定的规则,可以再多了解一些用法我不在赘述。
我们来了解它的常用方法。
1.match()方法
match()会从字符串的起始位置匹配正则表达式,如果匹配成功会输出匹配的结果,出错会返回None。
示例如下:

import re
content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match('^Hello\s(\d+)\sWorld', content)
print(result)
print(result.group())
print(result.span())

运行结果:

<re.Match object; span=(0, 19), match='Hello 1234567 World'>
Hello 1234567 World
(0, 19)

我们打印了这个输出可以看到是一个re.Match对象,这表明我们匹配成功了,该对象有两个方法group()方法可以输出正则表达式所匹配到的内容;span()方法可以输出匹配的范围。
匹配目标
我们貌似已经提取了匹配的内容。但是如果我们想要的仅仅是一段数字的电话呢?比如我们想把1234567这段数字匹配出来。这里就需要将数字部分用正则表达式括号括起来,然后再调用group(1)方法获取结果。1号索引是指数字所在的位置。
示例如下:

import re
content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match('^Hello\s(\d+)\s(World)', content)
print(result)
print(result.group(1))
print(result.group(2))  # 我们将World括起来了也可以调用World 但如果你调用Hello它会报错

运行结果:

<re.Match object; span=(0, 19), match='Hello 1234567 World'>
1234567
World

这里需要注意的是括号的问题!!!
通用匹配
我们上面写的正则表达式其实比较复杂,遇到数字就是\d,空白就是\s,这样匹配工作量确实不小,其实还要一种更好的方法万能匹配就是.*。

# 这里的.(点)代表的是可以匹配任意的字符*代表的是匹配前面的字符无数次。

有了它我们确实可以轻松不少,示例如下:

import re
content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match('^.*$', content)
print(result)

输出结果:

<re.Match object; span=(0, 40), match='Hello 1234567 World_This is a Regex Demo'>

是不是顿时简单了不少。看到这里是不是觉得多少有些疑惑看来这么久似乎并没有看到特别有用的东西,这些操作随便调用一些方法就能实现为什么还要专门学re呢?别急这仅仅是开始,如果能看完你大概就能明白!!!
贪婪与非贪婪
再使用上面.*的时候,有时可能匹配的不是我们想要的结果。
示例如下:

import re
content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match('^He.*(\d+).*$', content)
print(result)
print(result.group(1))

运行结果:

<re.Match object; span=(0, 40), match='Hello 1234567 World_This is a Regex Demo'>
7

运行结果仅有一个7,很奇怪!
这里就是贪婪与非贪婪的问题这里的.*会尽可能的匹配多的字符。我们再He后加上了.*,后面又跟了\d+,但是并没有说\d+需要匹配多少个,所以我们的.*就将123456全部匹配了仅留下了一个7给\d+匹配。
这就是贪婪匹配,这样会给我们带来很多的不便,因此我们再字符串中间尽量使用非贪婪匹配,就是用.*?代替.*来避免出现上述情况。
示例如下:

import re
content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match('^He.*?(\d+).*$', content)
print(result)
print(result.group(1))

运行结果:

<re.Match object; span=(0, 40), match='Hello 1234567 World_This is a Regex Demo'>
1234567

好的得出了我们想要的结果。
修饰符
正则表达式可以包含一些可选标识符来控制匹配的模式,修饰符被指定一个可选的标志。
示例如下:

import re
content = 'Hello 1234567 World_This \n is a Regex Demo'
result = re.match('^He.*?(\d+).*$', content)
print(result)
print(result.group(1))

运行结果:

None
Traceback (most recent call last):
  File "C:\python_couse\project_01\spider\request_01.py", line 7, in <module>
    print(result.group(1))
AttributeError: 'NoneType' object has no attribute 'group'

我们添加了一个换行符就报错了,那怎样才能正确的匹配换行呢?我们可以再match传入的参数中添加一个修饰符即可。
示例如下:

import re
content = 'Hello 1234567 World_This \n is a Regex Demo'
result = re.match('^He.*?(\d+).*$', content, re.S)
print(result)
print(result.group(1))

运行结果:

<re.Match object; span=(0, 42), match='Hello 1234567 World_This \n is a Regex Demo'>
1234567

结果正确,这个re.S我们在网页解析中会常用。
我们给出一些常用的修饰符表,可以根据需要添加:
在这里插入图片描述
图片来源:https://blog.csdn.net/qq_41542989/article/details/112045421
2.search
前面提到了match()方法是从头开始匹配的,一旦开始或者路径中的任何一处不匹配就会报出None。
示例如下:

import re
content = 'Hello 1234567 https://tool.oschina.net/regex/#'
result = re.match('^wo.*?(\d+).*$', content, re.S)
print(result)

运行结果:

None

可以看到我们没有匹配到任何的字符串,这样不适合我们再HTML文件中查早我们需要的数据,它更适合数据的校验。
我们在这里引入另一个方法search(),这个方法会扫描整个字符串返回我们第一个找到的结果,并且将匹配结果返回。比如我们要再网页中返回一串汉字字符。
示例如下:

import re
html = '''
<li>
<div><a href="https://child.baidu.com/" target="_blank">懂啦</a></div>
<div><a href="/item/秒懂本尊答" target="_blank">秒懂本人答</a></div>
<div><a href="/item/秒懂大师说" target="_blank">秒懂大师说</a></div>
<div><a href="/item/秒懂看瓦特" target="_blank">秒懂看瓦特</a></div>
<div><a href="/item/秒懂五千年" target="_blank">秒懂五千年</a></div>
<div><a href="/item/秒懂全视界" target="_blank">秒懂全视界</a></div>
</ li>'''
result = re.search('<div>.*?item/(.*?)".*?">(.*?)</div>', html, re.S)
print(result)
print(result.group(1))

运行结果:

<re.Match object; span=(6, 133), match='<div><a href="https://child.baidu.com/" target="_>
秒懂本尊答

search()方法会扫描整个文本,返回匹配到的第一个满足条件的结果。这里重要的括号()与re.S正则是基础,正则表达式如果感觉吃力慢慢看其实就是人们约定的规则。
3.findall
当然我们不可能仅仅需要一条结果,我们需要的往往是整个界面甚至更多,这里我们引入另外一个方法findall()。看这个就能明显的知道它是寻找字符串中的所有匹配字符,我们再来匹配一次汉字。
示例如下:

import re
html = '''
<li>
<div><a href="https://child.baidu.com/" target="_blank">懂啦</a></div>
<div><a href="/item/秒懂本尊答" target="_blank">秒懂本人答</a></div>
<div><a href="/item/秒懂大师说" target="_blank">秒懂大师说</a></div>
<div><a href="/item/秒懂看瓦特" target="_blank">秒懂看瓦特</a></div>
<div><a href="/item/秒懂五千年" target="_blank">秒懂五千年</a></div>
<div><a href="/item/秒懂全视界" target="_blank">秒懂全视界</a></div>
</ li>'''
result = re.findall('<div>.*?item/(.*?)".*?">(.*?)</a>', html, re.S)
print(result)

运行结果:

[('秒懂本尊答', '秒懂本人答'), ('秒懂大师说', '秒懂大师说'), ('秒懂看瓦特', '秒懂看瓦特'), ('秒懂五千年', '秒懂五千年'), ('秒懂全视界', '秒懂全视界')]

当我们仅需要提取第一个内容时我们可以用search(),需要全部内容时我们可以使用findall()。
4.sub
正则表达式除了用来提取信息外还可以用来修改文本。比如,把一串字符串中的所有数字去掉,你也可以使用replace()方法不过太繁琐了。
示例如下:

import re
content = '2345biafge85276hvzxfg3567'
content = re.sub('\d+','',content)
print(content)

运行结果:

biafgehvzxfg

我们剔除了数字,我们传入的第一个参数是指要匹配的字段,第二个参数是要替换为的字符串,第三个参数就是原字符串。
同样以html文本为例我们来将非数字的都替换为空,只保留数字。
示例如下:

import re
html = '''
<li>
<div><a href="https://child.baidu.com/" target="_blank">懂啦</a></div>
<div><a href="/item/秒懂本尊答" target="_blank">秒懂本人答</a></div>
<div><a href="/item/秒懂大师说" target="_blank">秒懂大师说</a></div>
<div><a href="/item/秒懂看瓦特" target="_blank">秒懂看瓦特</a></div>
<div><a href="/item/秒懂五千年" target="_blank">秒懂五千年</a></div>
<div><a href="/item/秒懂全视界" target="_blank">秒懂全视界</a></div>
</ li>'''
result = re.sub('<div>|</div>', '', html, re.S)
print(result)
result1 = re.findall('item/(.*?)".*?>(.*?)</a>', result, re.S)
for i in result1:
    print(i[0])

我们用sub()方法去掉了div标签,然后用findall()方法提取,正则表达式相比于直接用findall()要简单一些,我这里的例子不太好,可以自己找网页尝试。
运行结果:

<li>
<a href="https://child.baidu.com/" target="_blank">懂啦</a>
<a href="/item/秒懂本尊答" target="_blank">秒懂本人答</a>
<a href="/item/秒懂大师说" target="_blank">秒懂大师说</a>
<a href="/item/秒懂看瓦特" target="_blank">秒懂看瓦特</a>
<a href="/item/秒懂五千年" target="_blank">秒懂五千年</a>
<a href="/item/秒懂全视界" target="_blank">秒懂全视界</a>
</ li>
秒懂本尊答
秒懂大师说
秒懂看瓦特
秒懂五千年
秒懂全视界

我们用sub()方法可以将一些我们不需要的节点处理,然后再用findall()方法来提取能达到事半功倍的效果。
这些就是我认为再爬虫方面比较重要的点啦,如有需要也可也看看官方文档:https://docs.python.org/zh-cn/3/library/re.html

文章来源于图书笔记。

标签:匹配,1234567,python,content,re,详解,result,print
来源: https://blog.csdn.net/weixin_45471686/article/details/115748450