浅入浅出--正则表达式

正则表达式

为了打字方便我们称它为 –Regex
对长文本的处理是件很麻烦的是,我接触Regex是由于做爬虫的时候要处理很多HTML的tag,根据标签里的内容得到资源信息是件很麻烦的事情,但是有了正则后一切变得简单许多。

Python 的正则引擎 –RE
首先,当我们遇到一大段字符串String,我们想要怎么处理它呢?

  1. 也许我们想要拿它和已知的 pattern 对比,我们可以用到 Re.match()
  2. 或许我们想要在这个 String 里面找到某一个Pattern,看它是否出现,这时候可以用到 Re.search()
  3. 当做爬虫的时候,最常干的就是在抓到的网页内容里需找资源文件了,我们可以用到 Re.findall() 来找到所有匹配的URL~~~~
  4. 当然,Re.findall() 也可以被逼格更高的 Re.finditer() 代替,不同的是它返回的是一个迭代器对象,迭代器可以返回每一个匹配到的结果2233
  5. 如果想直接对字符串进行操作的话,也有两个选择 Re.split()re.sub()前者可以对字符串进行分割,而后者可以直接用字符串进行替换。

看了上面的介绍,你们大概就会发现,想要玩转正则表达式,必须掌握的就是Pattern–模式,也就是对于一大串要处理的 String 你所能提供的字符串信息。

这时候不得不简单介绍下最经典的 kmp (看maopian)算法了:


我们有一串字符串长度为 m 的 s1 ,想在这个 s1 里面找到可以完全匹配另一段短小的字串长度为 n 的 p1,看着挺简单不就几个for嵌套一下一个 char,一个 char 慢慢匹配么~~~。
OK,这样算的话复杂度 O(m*n) 可以分分钟恶心死你
而 kmp 的核心是对模式 p1 进行处理,找到模式本身的循环规则已达到降低复杂度到 O(m+n)的目的。


我们提到 kmp 是因为 Re中也有类似的过程,而该过程是通过Re.compile()方法来实现的。也就是说当我们想开始使用一个 pattern 进行匹配,第一步是对pattern 进行处理 如下

>>> import re
>>> s1 = 'xiaosfanaichifan'
>>> p1 = re.compile('xiaofan',[re.X])

p1 就是对 pattern 编辑后返回的对象。它的第二个参数是可选项。

re.I    re.IGNORECASE 区分大小写
re.L    re.LOACLE 根据位置匹配 \w \W \s \S \b \B。
re.M re.MUTILINE 用 ^ 和 $ 匹配目标字串的每一行而不是单纯的整个字串的开始和结束。
re.S re.DOTALL . 可以匹配到换行符

大家可以发现又出现了新的标志, $ ^ . \d \s ,这些先不介绍,稍后就会出现在我的文章中。而现在要做的当然就是开始匹配喽。

现在我们有一段字串 s1 = 'xiaosfanaichifan',还有一个 compile 后的object p1 = re.compile('xiaofan') ,compile的参数先不用。我们可以re.match() 方法来确定 pattern 与 s1 是否相匹配

>>> m1 = p1.match(s1)
>>> print m1.group()
xiaofan

当匹配成功时返回一个 match 对象。可以调用 group() 方法查看所以匹配到的分组。但是当我们使用字串 s2 = ‘123xiaofanaichifan’ 发现调用 match 后返回到的是 NUll

>>> s2 = '123xiaofanaichifan'
>>> p2 = re.compile('xiaofan')
>>> m2 = p2.match(s2)
>>> print m2
None 

匹配不了是因为 match 是从字串开头匹配的, 第一个字符对不上的话就没戏了~~
想要在一段字符串内搜索对应的 Pattern 的话,可以使用 re.search(),它和 match 一样,返回的也是 match object 。

>>> s2 = '123xiaofanaichifan'
>>> p2 = re.compile('xiaofan')
>>> m2 = p2.search(s2)
>>> m2
<_sre.SRE_Match object at 0x01F7C410>
>>> m2.group()
'xiaofan'
>>> m2.start()
3#表示从第3个字符开始

也可以用 re.findall() 方法找到所有匹配内容,如

>>> m2 = p2.findall(s2)
>>> m2
['xiaofan', 'xiaofan'] 

我在爬虫时用到最多就是这个了, 列出页面标签模式,并获取内容、获取json数据等,如新浪登陆页面中的第一个返回到的 content:

sinaSSOController.preloginCallBack({"retcode":0,"servertime":1444895970,"pcid":"xd-abc5f02b0481d7e5ea8b87dafbab338324bd","nonce":"YKJ12W","pubkey":"EB2A38568661887FA180BDDB5CABD5F21C7BFD59C090CB2D245A87AC253062882729293E5506350508E7F9AA3BB77F4333231490F915F6D63C55FE2F08A49B353F444AD3993CACC02DB784ABBB8E42A9B1BBFFFB38BE18D78E87A0E41B9B8F73A928EE0CCEE1F6739884B9777E4FE9E88A1BBE495927AC4A799B3181D6442443","rsakv":"1330428213","is_openlock":0,"showpin":1,"exectime":23})

我们想处理里面的JSON数据,需要把()中的数提取出来,构造如下模式:

>>>p = re.compile('\((.*?)\)')
>>>m1 = p.findall(content)
>>>print m1
{"retcode":0,"servertime":1444895970,"pcid":"xd-abc5f02b0481d7e5ea8b87dafbab338324bd","nonce":"YKJ12W","pubkey":"EB2A38568661887FA180BDDB5CABD5F21C7BFD59C090CB2D245A87AC253062882729293E5506350508E7F9AA3BB77F4333231490F915F6D63C55FE2F08A49B353F444AD3993CACC02DB784ABBB8E42A9B1BBFFFB38BE18D78E87A0E41B9B8F73A928EE0CCEE1F6739884B9777E4FE9E88A1BBE495927AC4A799B3181D6442443","rsakv":"1330428213","is_openlock":0,"showpin":1,"exectime":23}

p = re.compile('\((.*?)\)') 表示的是匹配括号内的所有内容,我们把原来不规则的字串转化成了 json 模块 可以处理的字串。


我们初步介绍了re 中的一些方法,接下来要介绍的是 Regex 的重中之重–特殊符号和字符
为什么需特殊符号和字符呢,我们可以想象一种情况,当我们想在匹未知的配邮箱字串时,我们并不知道它的用户名、邮箱域名是什么,我们就无法确定匹配模式 。同时我们也想用一种模式匹配出具有共性的一类字串。这时候就需要用到特殊符号了,如下

>>> s31 = 'xioafan@tom.com'
>>> s32 = 'xiaolei@sina.com'
>>> s33 = ''
>>> p3 = re.compile('\wssss+@\w+.com')
>>> m31 = p3.match(s31)
>>> m32 = p3.match(s32)
>>> m3.group()
'xioafan@tom.com'
>>> m32.group()
'xiaolei@sina.com'

('\w+@\w+.com') 进行简单分析,\w 表示匹配字符,+表示匹配至少1次。上述例子就很明了,可以匹配到 xxxxx@xxxxx.com 这样的字串。

下面开始对不同的 Special Symbol and Chars 进行举例说明

  • literal: 原文匹配,也就是匹配本字符串
  • |: 并列匹配,可以匹配符号两边的模式
  • . : dot 可以匹配到除过(\n)外的任意字符(re.S 可以让它能匹配到\n)
  • ^+str :匹配以 str 开头的字串
  • str+$:匹配以str结尾的字串
    举个例子
>>> s41 = 'fantasy'
>>> s42 = 'fan213dsadas21312312y'
>>> p4= re.compile('^fan.+y$')
>>> m41 = p41.match(s41)
>>> m42 = p42.match(s42)
>>> m41.group()
>'fantasy'
>>> m42.group()
'fan213dsadas21312312y'

上述例子中我们构造了以 ‘fan’ 开头、’y’结尾,中间包含任意飞换行符的字串。可以将模式分解为

 1. ^fan 匹配以fan开头
 2. .+  匹配至少一个非 \n 字符
 3. y$ 以 y 结尾

我们发现又出现了一个新的符号 + , 当我们使用 . 来匹配字符串时,我们肯定不希望手打出 N 个点出来。所以这时候我们就需要使用数量匹配符了

 1. +   匹配 至少一个前一个出现的符号
 2. *   匹配0个或者多个前一个出现的符号
 3. ?   匹配0个或者一个 前一个出现的符号
 4.{N} 匹配N个前一个出现的符号
 5.{m,n}匹配大于M小于N个符号

有了这些数量匹配符,我们就可以更轻松的完成匹配 ,例如我写爬虫的时候,扒到一个页面,想继续爬该页面的图片时,必须要获取里面的 url ,用正则可以轻松的得到

>>>content = '<img src="http://img1.bdstatic.com/static/common/pkg/fmdetail_fa8b62f.jpg"/>'
>>>p51 = re.compile('<img src="(.*?)"/>')
>>>URls = p51.findall(content)
>print URLs
>['http://img1.bdstatic.com/static/common/pkg/fmdetail_fa8b62f.jpg"']

通过findall() 得到所有满足条件的url的列表然后进行下步处理

To be Continue~~~~

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值