爬虫必学知识之正则表达式下篇

这是日常学python的第13篇原创文章

继上篇文章说了正则表达式的简单用法,那今天我们就继续说一下正则表达式的复杂的用法。好了,废话不多说,直接进入正题。

正则表达式

情景:当你想要匹配一个qq号,qq号码长度为5-10位,那根据上篇文章的说法,很容易就可以想到该正则:

[0-9]{5,10}

这样是可以的,但是当你匹配一个长度大于10的号码时就会出错,这时就会去该字符串的前10个数字出来,如下:

import re
a='221753259265'
r=re.findall('[0-9]{5,10}',a)#明显当查找的字符串长度大于8位时就会出错,只会截取前一部分长度
print(r)
# 结果
['2217532592']

这样的话你就会得到一个错误的qq号码。

这时就需要引入边界匹配了:

  • ^:这个是从左边开始匹配,规定左边的首个字符
  • $:这个是从右边开始匹配,规定右边的首个字母

现在再写个匹配qq号码的正则

r=re.findall('^[0-9]{5,10}$',a)#这个表示从左边起为5-10的数字长度,右边也是一样
print('第一个匹配结果:',r)
a = '2217532592'
r=re.findall('^[0-9]{5,10}$',a)
print('第二个匹配结果:',r)
# 结果
第一个匹配结果: []
第二个匹配结果: ['2217532592']

这样就可以匹配到了,是不是很神奇?

:前面我们有用 [ ] 来匹配,中括号里面表示的是或关系,而这里的组表示的是并关系,并且用小括号括起来 ( )

比如:重复 python 字样三次

import re
a='pythonpythonpythonjakjpythonpythonsdjjpythonpythonpythonsd'
r=re.findall('(python){3}',a)
print(r)
# 结果
['python', 'python']

这里的结果不是返回三个python,而是返回这个组,当符合一次就会将此组添加到返回列表中一次。

这个组还挺好用的,再看下这个需求:获取下列英文中的life和python之间的内容。

a='life is short,i use python'
r=re.findall('life(.*)python',a,re.S)
print(r) # 这样获取的就是组内的内容
# 结果
[' is short,i use ']

这个组还常用,因为在我们经常在用正则来解析html元素时,经常需要获取两个标签之间的内容,标签是确定的,标签内容不确定,就可以用这个了。如下这个html元素:

<strong><a href="#py2">python进阶 </a>
            <a href="#python3">python入门 </a>
        <a href="#vce">vce解决方法 </a>
        <a href="demo06.html#new" target="_blank">百度 </a>
        <a href="mailto: 2217532592@qq.com">反馈意见</a>
        <a href="img/1.jpg">下载图片 </a>
    </strong>

这样就可以用组来获取a标签的内容了:<a .*?>(.*?)</a>。?表示非贪婪哦!

re.findall(pattern,string,flags):这个方法的前两个参数对你们来说都很熟悉了,第一个参数为正则表达式,第二个参数为要进行匹配的字符串,而第三个可选参数为匹配模式,有如下几种匹配模式:

  • re.I(re.IGNORECASE) :使匹配对大小写不敏感
  • re.L(re.LOCAL):做本地化识别(locale-aware)匹配
  • re.M(re.MULTILINE):多行匹配,影响 ^ 和 $
  • re.S(re.DOTALL):使 . 匹配包括换行在内的所有字符(这个常用)
  • re.U(re.UNICODE):根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B.
  • re.X(re.VERBOSE):该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解

当需要写多个匹配模式时,可以用 | 分隔每个模式

代码如下:

a='Java12Python89'
r=re.findall('python',a,re.I)
print(r)
a='hsjhj h123jfkksf hajkGH\nkj fjfk'
r=re.findall('.',a,re.I|re.S)
print(r)
# 结果
['Python']
['h', 's', 'j', 'h', 'j', ' ', 'h', '1', '2', '3', 'j', 'f', 'k', 'k', 's', 'f', ' ', 'h', 'a', 'j', 'k', 'G', 'H', '\n', 'k', 'j', ' ', 'f', 'j', 'f', 'k']

正则除了可以用来检索字符串,还可以用来替换字符串,常见的可以用来替换那些文本中的空格,制表符和回车等,这些都是用一个正则就可以搞定的了。

python中用这个方法来进行正则替换

re.sub(pattern, repl, string, count=0, flags=0)

  • pattern :正则表达式
  • repl :替换后的字符串,可为函数
  • string :要进行替换的字符串
  • count :替换的次数,顺序为 从左往右,默认值为0,表示无限次。
  • falgs : 匹配模式,和findall()差不多

代码如下:

import re
a='skjC#ksjfc#jkdsc#'
r=re.sub('c#','gg',a)#返回值是替换后的字符串
print(r)
print(a)
r=re.sub('c#','gg',a,1) # 这个加了替换次数
print(r)
r=re.sub('c#','gg',a,1,re.I) # 加了匹配模式,忽视大小写
print(r)
# 结果
skjC#ksjfggjkdsgg
skjC#ksjfggjkdsc#
skjggksjfc#jkdsc#

我们试试第二个参数为函数的情况

def convert(value):#他是把对象传进去这个参数
    print(value)
    #可以通过group()方法来获取内容
    return '!!'+value.group()+"!!"
r=re.sub('c#',convert,a,flags=re.I)#接收个参数后,更改后的内容为他的返回值
print(r)
# 结果
<_sre.SRE_Match object; span=(3, 5), match='C#'>
<_sre.SRE_Match object; span=(9, 11), match='c#'>
<_sre.SRE_Match object; span=(15, 17), match='c#'>
skj!!C#!!ksjf!!c#!!jkds!!c#!!

这个第二个参数为convert函数,里面的.group() 方法是获取匹配后的字符串的值,所以我们就可以根据匹配后的字符串来进行相对应的替换内容,比如这个简单的小需求:

把字符串中的数字大于50的改为99,小于的就改为11。

a='ds+45sd78asd12568asd45asd74ew+9ddf12sd45'
def func(value):
    if int(value.group())>50:
        return '99'
    else:
        return '11'

r=re.sub('\d{1,2}',func,a)
print(r)
# 结果
ds+11sd99asd119911asd11asd99ew+11ddf11sd11

另谈两个函数

  • re.match(pattern,string,flags) :这个是从字符串的首个字母开始匹配,若首个字母不符合,就会返回None, 反之返回一个 Match对象。而他只会匹配第一个结果,不会返回所有符合结果的内容。参数内容与findall()方法一样。
  • re.search(pattern,string,flags) :这个与match方法差不多,不过不是从首字符开始匹配,也是只返回一个正确的匹配内容。

代码:

import re
a='pythonphpjavacphp'
r=re.match('php',a)#这个一开始没有就返回None
print(r)
r=re.search('php',a)#这个搜索到之后就返回一个对象
#返回的对象可以通过group()方法来获取他的内容
print(r)
# 获取匹配内容
print(r.group())
# 结果
None
<_sre.SRE_Match object; span=(6, 9), match='php'>
php

这两个函数返回的内容的几个属性:

  • group() :获取匹配的内容
  • statr() :获取到匹配字符的起始位置
  • end() :获取匹配到字符的结束位置
  • span() :获取匹配到字符的起始和结束位置,元组形式返回。

前面提到组的概念,试下这两个方法的组的用法:

import re
#获取life和python之间的内容
a='life is short,i use python'
r=re.search('life(.*)python',a,re.S)#用小括号的就是一组
print(r.group(1))#这个下标1就是对应的中间部分

#也可以获取中间的两部分
a='javawoshipythonjunephp'
r=re.search('java(.*)python(.*)php',a)#两个小括号就是分成了两组
print(r.group(1),r.group(2))#分别打印第一第二组
print(r.groups())#这个获取所有分组信息
# 结果
 is short,i use 
woshi june
('woshi', 'june')

上面的代码注释已经很清楚了,还有个group()方法是获取整个正则匹配的内容,不按分组。match()方法也一样,就不演示了。

最后一个问题:怎样拆分含有多种分隔符的字符串?

比如:kfs;hsji'fhsikf*bhsfk=jsf/shj。要将不属于字母的都去掉,你是不是会想到用字符串的循环,然后再一个一个分割出来?我告诉你,学了正则之后,再也不用这么麻烦了。re库里面有个split()方法,如下:

re.split(pattern, string, maxsplit=0),参数看名字应该就能知道。直接一行代码进行分割:

a = 'kfs;hsjifhsikf*bhsfk=jsf/shj'
r = re.split('[;*=/]', a)
print(r)
# 结果
['kfs', 'hsjifhsikf', 'bhsfk', 'jsf', 'shj']

是不是很完美?所以说正则必须得学!

END

这个正则复杂点的已经说完了,还有些进阶的,不过暂时没有用到,就不打算说了,需要的可以去百度看看哈!

留个小练习证明自己正则学得好怎么样:

1.kevintian126@126.com

2. 1136667341@qq.com

3. meiya@cn-meiya.com

4. wq901200@hotmail.com

5. meiyahr@163.com

6. meiyuan@0757info.com

7. chingpeplo@sina.com

8. tony@erene.com.com

9. melodylu@buynow.com

用正则把上面的@与com之间的内容匹配出来,可以把你的答案写在留言区上,过两天在留言区公布答案哈!

上述文章如有错误欢迎在留言区指出,如果这篇文章对你有用,点个赞,转个发如何?

原文发布于微信公众号 - 日常学python(daily_learn)

原文发表时间:2018-03-20

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏源哥的专栏

BASE64编码

附录:BASE64编码的原理(节选自http://www.vbzx.net/ArticleView/vbzx_Article_View_1199.asp)

984
来自专栏Java后端技术

这个坑,是时候填上了~

​  这两天,在网上逛的时候,发现了如下的一道面试题,感觉还有蛮有意思的,要是不仔细看还真容易掉到坑里面。第一眼看起来比较绕,所以比较难理解。最终我跳出了这个坑...

741
来自专栏SeanCheney的专栏

《利用Python进行数据分析·第2版》第3章 Python的数据结构、函数和文件3.1 数据结构和序列3.2 函数3.3 文件和操作系统3.4 结论

本章讨论Python的内置功能,这些功能本书会用到很多。虽然扩展库,比如pandas和Numpy,使处理大数据集很方便,但它们是和Python的内置数据处理工具...

4736
来自专栏kevindroid

JNI所需的C语言知识小结

1685
来自专栏Java架构师学习

为Java程序员金三银四精心挑选的五十道面试题与答案

1、面向对象的特征有哪些方面? 【基础】 答:面向对象的特征主要有以下几个方面: 1)抽象:抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地...

3636
来自专栏函数式编程语言及工具

泛函编程(5)-数据结构(Functional Data Structures)

     编程即是编制对数据进行运算的过程。特殊的运算必须用特定的数据结构来支持有效运算。如果没有数据结构的支持,我们就只能为每条数据申明一个内存地址了,然后使...

2166
来自专栏游戏开发那些事

【读书笔记】读《程序员面试宝典》

  最近有幸拜读了《程序员面试宝典》(第五版)这本书,此书真乃良心之作,尤其对于我们这种未毕业的学生来说,更是一本不可多得的宝贵资料。

2982
来自专栏农夫安全

python爬虫基础之正则表达式

Python基础前期后后看了五六遍,除了能读懂一些简单的代码,一直也没有进阶。 这次借助一个爬虫教学视频。把学习中的一些重点写下来,一个是自己巩固,一个是也帮助...

4367
来自专栏用户2442861的专栏

static_cast, dynamic_cast, reinterpret_cast, const_cast区别

(使用vs2010所带的编译器) 转载请注明来源 http://www.cnblogs.com/jerry19880126/

912
来自专栏向治洪

模板方法模式

概述 概念:定义一个操作中算法的框架,而将一些步骤延迟到子类中,使得子类可以不改变算法的结构即可重定义该算法中的某些特定步骤。模板方法模式属于行为类模式。 模板...

2077

扫码关注云+社区

领取腾讯云代金券