正则表达式是一个很强大的字符串处理工具,几乎任何关于字符串的操作都可以使用正则表达式来完成,作为一个爬虫工作者,每天和字符串打交道,正则表达式更是不可或缺的技能,正则表达式的在不同的语言中使用方式可能不一样,不过只要学会了任意一门语言的正则表达式用法,其他语言中大部分也只是换了个函数的名称而已,本质都是一样的。下面,我来介绍一下python中的正则表达式是怎么使用的
正则表达式模式
模式字符串使用特殊的语法来表示一个正则表达式:
字母和数字表示他们自身。一个正则表达式模式中的字母和数字匹配同样的字符串。
多数字母和数字前加一个反斜杠时会拥有不同的含义。
标点符号只有被转义时才匹配自身,否则它们表示特殊的含义。
反斜杠本身需要使用反斜杠转义。
由于正则表达式通常都包含反斜杠,所以你最好使用原始字符串来表示它们。模式元素(如 r'\t',等价于 '\\t')匹配相应的特殊字符。下表列出了正则表达式模式语法中的特殊元素。如果你使用模式的同时提供了可选的标志参数,某些模式元素的含义会改变。
[...] 用来表示一组字符,单独列出:[amk]匹配a,m或k
[^...] 不在[]中的字符:[^amk]匹配除amk之外的字符
re* 匹配0个或多个的表达式
re+ 匹配1个或多个的表达式
re? 匹配0个或1个由前面的正则表达式定义的片段,非贪婪方式.
re{n} 精准匹配n个前面表达式
re{n,} 匹配大于等于n个前面表达式
re{n,m} 匹配n到m个前面的表达式定义的片段,贪婪方式
a|b 匹配a或b
(re) 对正则表达式分组,并记住匹配的文本
(?imx) 正则表达式包含三种可选标志,imx,只影响括号中的区域.
(?-imx) 正则表达式关闭imx可选标志,只影响括号中的区域.
(?:re) 类似(...)但不表示一个组
(?imx:re) 在括号中使用imx可选标志
(?-imx:re) 在括号中不是用imx可选标志
(?#...) 注释
(?=re) 前向肯定界定符.如果所含正则表达式,以...表示,在当前位置成功匹配时成功,否则失败.但一旦所含表达式已经尝试,匹配引擎根本没有提高,模式的剩余部分还要尝试界定符右边.
(?!re) 前向否定界定符.与肯定界定符相反;当所含的表达式不能在字符串当前位置匹配成功时成功.
(?>re) 匹配的独立模式,省去回朔.
^ 匹配字符串开头
$ 匹配字符串结尾
. 匹配除换行之外的一个字符.当re.DOTAALL标记被指定时,则可以匹配包括换行符的任意字符.
*匹配*号前一个字符0次或多次
+匹配前一个字符1次或多次
?匹配前一个字符1次或0次
\w 匹配字符数字以及下划线,相当于类 [a-zA-Z0-9_]
\W 匹配非字母数字下划线,相当于类 [^a-zA-Z0-9_]
\s 匹配任意空白字符,等价于[\t\n\r\f]
\S 匹配任意非空白字符
\d 匹配任意数字,相当于类 [0-9]
\D 匹配任意非数字,相当于类 [^0-9]
\A 匹配字符串开始
\Z 匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串.
\z 匹配字符串结束
\G 匹配最后匹配完成的位置
\b 匹配一个单词边界,也就是指单词和空格之间的位置
\B 匹配非单词边界
\n \t 匹配一个换行符,一个制表符
\1...\9 匹配第n个分组的内容
# 正则表达式实例:
# 实例: 描述:
# [Pp]ython 匹配 "Python" 或 "python"
# rub[ye] 匹配 "ruby" 或 "rube"
# [aeiou] 匹配中括号内的任意一个字母
# [0-9] 匹配任何数字。类似于 [0123456789]
# [a-z] 匹配任何小写字母
# [A-Z] 匹配任何大写字母
# [a-zA-Z0-9] 匹配任何字母及数字
# [^aeiou] 除了aeiou字母以外的所有字符
# [^0-9] 匹配除了数字外的字符
re.search().group()
# re.search 扫描整个字符串并返回第一个成功的匹配,如果匹配失败search()就返回None。
#我们可以使用group(num) 或 groups() 匹配对象函数来获取匹配表达式
# re.search(pattern, string, flags=0)
# pattern匹配的正则表达式
# string要匹配的字符串。
# flags标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。# group(num=0)匹配的整个表达式的字符串,group() 可以一次输入多个组号,将返回一个包含那些组所对应值的元组。
# groups()返回一个包含所有小组字符串的元组
re.findall()
#findall在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。
#注意: match 和 search 是匹配一次 findall 匹配所有。
# findall(pattern, string, flags=0)
pattern 为正则表达式
string 为待操作字符串
flags 为所用模式
re.split()
split 根据匹配进行切割字符串,并返回一个列表
ret1 = re.split(":","胖子老板:一包烟17元啦")
print(ret1)
['胖子老板', '一包烟17元啦']
#据多个条件进行切割
ret2 = re.split(r":|\s","胖子老板:一包烟17元啦 肥仔白: 这么贵啊!")
print(ret2)
['胖子老板', '一包烟17元啦', '肥仔白', '', '这么贵啊!']
案例一:
#提取第一个匹配项
line1 = r'<a href="/ershoufang/minhang/" title="上海闵行在售二手房 ">闵行</a><meta' \
r'name="description" content="上海链家二手房频道,发布上海二手房真实在售房源信息,' \
r'为您提供上海二手房房源出售、二手房买卖交易等信息,快速查询上海二手房房价、特色、' \
r'带看情况等.链家,连接每个家的故事."<a href="/ershoufang/hongkou/" title="上海虹口在售二手房 ">虹口</a>' \
r'<a href="/ershoufang/qingpu/" title="上海青浦在售二手房 ">青浦</a>' \
r'<a href="/ditiefang/li143685036/" title="上海1号线在售二手房 ">1号线</a>' \
r'<a href="/ditiefang/li110460733/" title="上海16号线在售二手房 ">16号线</a>>'
#匹配上第一个地铁线
print(re.search(".号线",line1).group())
#匹配上第一个数字
print(re.search("[0-9]",line1).group())
#匹配所有地铁线
print(re.findall(".号线",line1))
#匹配所有数字段
print(re.findall("\d+",line1))
#匹配所有非字母段
print(re.findall('[^a-z^A-Z]+',line1))
#匹配所有标签内的
print(re.findall('<a href=(.+?)>',line1))
1号线
1
['1号线', '1号线', '6号线', '6号线']
['143685036', '1', '1', '110460733', '16', '16']
['<', ' ', '="/', '/', '/" ', '="上海闵行在售二手房 ">闵行</', '><', '="', '" ', '="上海链家二手房频道,发布上海二手房真实在售房源信息,为您提供上海二手房房源出售、二手房买卖交易等信息,快速查询上海二手房房价、特色、带看情况等.链家,连接每个家的故事."<', ' ', '="/', '/', '/" ', '="上海虹口在售二手房 ">虹口</', '><', ' ', '="/', '/', '/" ', '="上海青浦在售二手房 ">青浦</', '><', ' ', '="/', '/', '143685036/" ', '="上海1号线在售二手房 ">1号线</', '><', ' ', '="/', '/', '110460733/" ', '="上海16号线在售二手房 ">16号线</', '>>']
['"/ershoufang/minhang/" title="上海闵行在售二手房 "', '"/ershoufang/hongkou/" title="上海虹口在售二手房 "', '"/ershoufang/qingpu/" title="上海青浦在售二手房 "', '"/ditiefang/li143685036/" title="上海1号线在售二手房 "', '"/ditiefang/li110460733/" title="上海16号线在售二手房 "']
案例二:
line2=r"[转让] Z77 北京-武汉 硬卧 1张 发车日期:12-26 http://www.huochepiao.com/Info/2007-12/TWG2007122114001.htm" \
" MB_13401008452[转让] Z77 北京-武汉 硬卧 1张 发车日期:12-26" \
"http://www.huochepiao.com.cn/Info/2007-12/TWG2007122114001.htm MB_13401008452"
#提取.com和.com.cn域名的中间部分
print(re.findall(r'http://(.+?)/',line2))
#提取.com和.com.cn域名的中间全部
print(re.findall(r'http://.+?/',line2))
['www.huochepiao.com', 'www.huochepiao.com.cn']
['http://www.huochepiao.com/', 'http://www.huochepiao.com.cn/']
案例三:
line3= """http://www.interoem.com/messageinfo.asp?id=35
http://3995503.com/class/class09/news_show.asp?id=14
http://lib.wzmc.edu.cn/news/onews.asp?id=769
http://www.zy-ls.com/alfx.asp?newsid=377&id=6
http://www.fincm.com/newslist.asp?id=415"""
#提取.com或.cn
print(re.findall("http://.*?.com|http://.*?.cn", line3))
print(re.findall("http://(.*?).com|http://(.*?).cn", line3))
['http://www.interoem.com', 'http://3995503.com', 'http://lib.wzmc.edu.cn', 'http://www.zy-ls.com', 'http://www.fincm.com']
[('www.interoem', ''), ('3995503', ''), ('', 'lib.wzmc.edu'), ('www.zy-ls', ''), ('www.fincm', '')]
案例四:
line4= '<img class="course-banner lazy" data-original="//img4.hhhaaa.com/5a405d45000175cb06000338-240-135.jpg"' \
' src="//img4.hhhaaa.com/5a405d45000175cb06000338-240-135.jpg" style="display: inline;">'
#提取多个jpg中的第一个全部
print(re.search('<img class="course-banner lazy" data-original="(.*?)"',line4).group())
#提取多个jpg中的第一个部分
print(re.search('<img class="course-banner lazy" data-original="(.*?)"',line4).group(1))
<img class="course-banner lazy" data-original="//img4.hhhaaa.com/5a405d45000175cb06000338-240-135.jpg"
//img4.hhhaaa.com/5a405d45000175cb06000338-240-135.jpg
案例五:提取字典中的中文
text ={"exclusive":0,"name":"哈哈"}
print(re.findall("[\u4e00-\u9fa5]+",str(text)))
print(re.findall("[\u4e00-\u9fa5]",str(text)))
"C:\Program Files\Python35\python.exe" C:/Users/wangli/PycharmProjects/Test/Test/test.py
['哈哈']
['哈', '哈']
Process finished with exit code 0