什么是正则表达式
正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、以及这些特定字符的组合,组成一个“规则字符串”,这个规则字符串用来表达对字符串的一种过滤逻辑
Python用re模块实现
其中有许多常用的正则表达式,非常好用。
一般的网页可以用beautifulsoup等解析库来提取,不过有的网页卸载js的变量中,只能使用正则表达式来提取。正则表达式可以用来筛选和清洗。非常有用。
python中的正则表达式讲解
- 常见匹配模式
模式 | 描述 |
---|---|
\w | 匹配字母数字及下划线 |
\W | 匹配非字母数字下划线 |
\s | 匹配任意空白字符、等价于[\t\n\r\f] |
\S | 匹配任意非空字符 |
\d | 匹配任意数字,等价于[0-9] |
\D | 匹配任意非数字 |
\A | 匹配字符串的开始 |
\Z | 匹配字符串结束,如果存在换行,只匹配到换行前的结束字符串 |
\z | 匹配字符串结束 |
\G | 匹配最后匹配完成的位置 |
\n | 匹配一个换行符 |
\t | 匹配一个制表符 |
^ | 匹配字符串的开头 |
$ | 匹配字符串的结尾 |
. | 匹配任意字符,除了换行符,当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符 |
[...] | 用来表示一组字符,单独列出:[osi]匹配‘o’,'s','j' |
[^...] | 匹配除括号中内容之外的字符 |
* | 匹配0个过多个表达式 |
+ | 匹配1个或多个表达式 |
? | 匹配0个或者1个表达式 |
{n} | 精确匹配n个前面的表达式 |
{n,m} | 匹配n到m此有前面的正则表达式定义的片段,贪婪方式 |
a|b | 匹配a或b |
() | 匹配括号内的表达式,也表示一个组 |
- re.match
re.match 尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none。
re.match(pattern,string,flags=0)
sample
1.常规的匹配
import re content = 'Hello 3232 4324 World_This is a Regex Demo' print(len(content)) result = re.match('^Hello\s\d{4}\s\d{4}\s\w{10}.*mo$',content) print(result) print(result.group())#匹配结果 print(result.span())#匹配结果在content中的范围
2.泛匹配--用.* 表示任意字符
import re content = 'Hello 3232 4324 World_This is a Regex Demo' result = re.match('^Hello.*mo$',content) print(result) print(result.group()) print(result.span())
3.匹配目标
一般我们把匹配目标用小括号括起来,然后指定左右端点,才能找到。
import re content = 'Hello 3232 4324 World_This is a Regex Demo' result = re.match('^Hello\s(\d{4})\s(\d+)\s.*mo$',content) print(result) print(result.group(1))#第一个小括号括起来匹配的内容 print(result.group(2))#第二个小括号括起来的内容 print(result.span())
4.贪婪匹配
import re content = 'Hello 3232 4324 World_This is a Regex Demo' result = re.match('^He.*(\d+).*mo$',content) print(result) print(result.group(1)) print(result.span())
*结果是4,因为.*表示任意字符,默认贪婪模式会匹配尽量多的任意字符,而\d+至少要匹配一个数字,所以就一直匹配到最后一个数字之前。
5.非贪婪模式
import re content = 'Hello 3232 4324 World_This is a Regex Demo' result = re.match('^He.*?(\d+).*mo$',content) print(result) print(result.group(1)) print(result.span())
.*?是非贪婪模式,匹配尽可能少字符。
6.匹配模式
import re content = "Hello 3232 4324 World_This \nis a Regex Demo\n" result = re.match('^He.*?(\d+).*mo$',content) print(result)
*结果为none,原因是.不能匹配换行符,修改之后可以匹配
import re content = "Hello 3232 4324 World_This \nis a Regex Demo\n" result = re.match('^He.*?(\d+).*mo$',content,re.S) print(result)
添加re.S后即可
7.转义
正则表达式中的许多特殊字符如果不做转义就无法匹配,会被认为是关键字使用,比如*.[]等等。以下就是不转义的例子
import re content = 'price $50.09' result = re.match('price $50.09',content) print(result)
结果返回none,没匹配到。
转义之后才能匹配
import re content = 'price $50.09' result = re.match('price \$50\.09',content) print(result)
最常见用法总结,尽量使用泛匹配模式,使用括号得到匹配目标,尽量使用非贪婪模式,使用re.S,因为HTML中有大量的换行符这样.就能匹配任意字符了。
- re.search
re.match从字符串的开头匹配,比如pattern无法匹配content的第一个字符,那么直接返回none。而re.search会搜索整个字符串,只要搜索到符合pattern的内容就返回第一个成功的匹配。以下是sample。
import re content = "jlljjljh Hello 1234 World_This is a Regex Demo,Don't forget!$" result = re.match('Hello.*?(\d+).*?',content) print(result)#用match的话,result返回none result = re.search('Hello.*?(\d+).*?',content) print(result)#可以匹配 print(result.group(1))#返回1234
总结,尽量用re.search方法,尽量使用re.S,用非贪婪模式
练习
import re html = '<div class="songList songList960 clearfix"><ol id="f1"><li><input type="checkbox" value="11417@" name="Url" class="check"> <span class="songNum topRed">01.</span> <a target="_1" href="/play/11417.htm" class="songName cBlue">大海</a></li><li><input type="checkbox" value="64541@" name="Url" class="check"> <span class="songNum topRed">02.</span> <a target="_1" href="/play/64541.htm" class="songName">天路</a></li><li><input type="checkbox" value="65937@" name="Url" class="check"> <span class="songNum topRed">03.</span> <a target="_1" href="/play/65937.htm" class="songName">再回首</a></li><li><input type="checkbox" value="59930@" name="Url" class="check"> <span class="songNum">04.</span> <a target="_1" href="/play/59930.htm" class="songName cBlue">突然的自我</a></li><li><input type="checkbox" value="1462@" name="Url" class="check"> <span class="songNum">05.</span> <a target="_1" href="/play/1462.htm" class="songName">甘心情愿</a></li></ol></div>' result = re.search('songName.*?>(.*?)</a>.*',html,re.S) print(result) print(result.group(1))
匹配结果:大海
- re.findall--搜索字符串,以列表形式返回全部能匹配的子串
import re html = '<div class="songList songList960 clearfix"><ol id="f1"><li><input type="checkbox" value="11417@" name="Url" class="check"> <span class="songNum topRed">01.</span> <a target="_1" href="/play/11417.htm" class="songName cBlue">大海</a></li><li><input type="checkbox" value="64541@" name="Url" class="check"> <span class="songNum topRed">02.</span> <a target="_1" href="/play/64541.htm" class="songName">天路</a></li><li><input type="checkbox" value="65937@" name="Url" class="check"> <span class="songNum topRed">03.</span> <a target="_1" href="/play/65937.htm" class="songName">再回首</a></li><li><input type="checkbox" value="59930@" name="Url" class="check"> <span class="songNum">04.</span> <a target="_1" href="/play/59930.htm" class="songName cBlue">突然的自我</a></li><li><input type="checkbox" value="1462@" name="Url" class="check"> <span class="songNum">05.</span> <a target="_1" href="/play/1462.htm" class="songName">甘心情愿</a></li></ol></div>' result = re.findall('songName.*?>(.*?)</a>.*?',html) print(result)
返回值:['大海', '天路', '再回首', '突然的自我', '甘心情愿'] *
- re.sub---替换字符串中每一个匹配的子串后返回替换后的字符串。
import re content = 'Hello 3232 4324 World_This is a Regex Demo' content = re.sub('\d+','',content)#把数字替换为空 print(content)
import re content = 'Hello 3232 4324 World_This is a Regex Demo' content = re.sub('\d+','Replacement',content)#数字部分都替换成‘replacement’ print(content)
如果替换的结果包含想替换的内容怎么办,比如像把这2段数字前面加上No.,但数字要保留,怎么办?
import re content = 'Hello 3232 4324 World_This is a Regex Demo' content = re.sub('(\d+)',r'No.\1',content)#用r''中间的是原生字符串不用转义了。先把patten小括号括起来,替换内容加\n.这个n表示第几个小括号的内容替换成这样。 print(content)
结果:Hello No.3232 No.4324 World_This is a Regex Demo
- re.compile---将正则字符串编译成正则表达式对象
将正则字符串编译成正则表达式对象,便于复用该匹配模式
import re content = 'Hello 3232 4324 World_This is a Regex Demo' result = re.match('^He.*?(\d+).*mo$',content,re.S)#用正则字符串匹配 myPatten = re.compile('^He.*?(\d+).*mo$',re.S)#编译正则表达式对象。 result = re.match(mypatten,content)#2种方法一样 print(result)
- 例子
爬取豆瓣读书
读取 https://book.douban.com 新书速递中的书名、作者、出版社
import requests import re content = requests.get('https://book.douban.com/').text #print(content) pattern = re.compile('<li.*?cover.*?href="(.*?)".*?title="(.*?)".*?more-meta.*?author">(.*?)</span>.*?year">(.*?)</span>.*?</li>',re.S) #print(pattern) results = re.findall(pattern,content) print(results)