常用模块二---re模块、正则表达式

一、正则表达式(re模块)

** 好书推荐:《正则指引》 爬虫方向必备

就其本质而言,正则表达式(或 RE)是一种小型的、高度专业化的编程语言,(在Python中)它内嵌在Python中,并通过 re 模块实现。正则表达式模式被编译成一系列的字节码,然后由用 C 编写的匹配引擎执行。

字符匹配(普通字符,元字符):

1 普通字符:大多数字符和字母都会和自身匹配
              >>> re.findall('alvin','yuanaleSxalexwupeiqi')
                      ['alvin'] 

2 元字符:. ^ $ * + ? { } [ ] | ( ) \

3常用方式

re.findall  返回所有的匹配项

re.search  只匹配一项符合规则的元素,返回对象,.group查看

re.match  只匹配字符串开始的位置,返回对象,.group查看

1、元字符

. ^ $

  .匹配除了换行符(\n)外的任意字符

  ^匹配字符串开头

  $匹配字符串结尾

复制代码
import re
print(re.findall('李.','李爽\nalex\n李四\negon\nalvin\n李二'))
#运行结果
['李爽', '李四', '李二']

ret=re.search('李.','李爽\nalex\n李四\negon\nalvin\n李二')
print(ret,ret.group(),ret.span())
#运行结果
<_sre.SRE_Match object; span=(0, 2), match='李爽'> 李爽 (0, 2)

ret=re.match('李.','李爽\nalex\n李四\negon\nalvin\n李二')
print(ret,ret.group(),ret.span())
#运行结果
<_sre.SRE_Match object; span=(0, 2), match='李爽'> 李爽 (0, 2)

print(re.findall('^李.','李爽\nalex\n李四\negon\nalvin\n李二'))
#运行结果
['李爽']

print(re.findall('李.$','李爽\nalex\n李四\negon\nalvin\n李二'))
#运行结果
['李二']
复制代码

* + ? { }

  *匹配前一个字符0个或任意多个

  +匹配前一个字符1个或任意多个

  ?匹配前一个字符0个或任意1个

  {}匹配前一个字符定义个数个

复制代码
import re
print(re.findall('李.*','李杰\nalex\n李莲英\negon\nalvin\n李二棍子'))
#运行结果
['李杰', '李莲英', '李二棍子']

print(re.findall('李.+','李杰\nalex\n李莲英\negon\nalvin\n李二棍子'))
#运行结果
['李杰', '李莲英', '李二棍子']

print(re.findall('李.{1,2}\n','李杰\nalex\n李莲英\negon\nalvin\n李二棍子'))
#运行结果
['李杰\n', '李莲英\n']

print(re.findall('\d+\.?\d*','12.45,34,0.05,109'))  # 匹配一个数字包括整型和浮点型
#运行结果
['12.45', '34', '0.05', '109']
复制代码

注意:前面的*,+,?等都是贪婪匹配,也就是尽可能匹配,后面加?号使其变成惰性匹配

print(re.findall('131\d+?','1312312312'))
#运行结果
['1312']

转义符\

1、反斜杠后边跟元字符去除特殊功能,比如\.

2、反斜杠后边跟普通字符实现特殊功能,比如\d

复制代码
\d      匹配任何十进制数;          它相当于类 [0-9]。
\D      匹配任何非数字字符;        它相当于类 [^0-9]。
\s      匹配任何空白字符;          它相当于类 [ \t\n\r\f\v]。
\S      匹配任何非空白字符;        它相当于类 [^ \t\n\r\f\v]。
\w      匹配任何字母数字字符;     它相当于类 [a-zA-Z0-9_]。
\W      匹配任何非字母数字字符;   它相当于类 [^a-zA-Z0-9_]
\b      匹配一个特殊字符边界,比如空格 ,&,#等 
复制代码
print(re.findall(r'I\b','I am LIST'))
#运行结果
['I']
复制代码
#匹配abc\le”中的‘c\l’:
print(re.findall('c\\\l','abc\le'))
print(re.findall('c\\\\l','abc\le'))
print(re.findall(r'c\\l','abc\le'))
#运行结果
['c\\l']

print(re.findall(r'c\\b',r'abc\be'))
#运行结果
['c\\b'] 
复制代码

分组()

复制代码
print(re.findall(r'(ad)+', 'add,adddd'))  #只返回元组的内容
#运行结果
['ad', 'ad']

ret=re.search('(?P<id>\d{2})/(?P<name>\w{3})','23/com')  #?P<'变量名'>进行命名
print(ret.group(),ret.group(1),ret.group(2))
print(ret.group('id'))
#运行结果
23/com    23    com
23
复制代码

或|

print(re.findall('ab|\d','rabhdg8sd'))
#运行结果
['ab', '8']

字符集[]

  [ab]匹配字符集中的一个字符

  -  \  ^ 在[]中有特殊意义

复制代码
print(re.findall('a[bc]d','abd'))
print(re.findall('[abc]','abc'))
print(re.findall('[.*+]','a.bc+'))
#运行结果
['abd']
['a', 'b', 'c']
['.', '+']

#在字符集里有功能的符号: - ^ \
print(re.findall('[1-9]','45dha3'))
print(re.findall('[^ab]','45bdha3'))
print(re.findall('[\d]','45bdha3'))
#运行结果
['4', '5', '3']
['4', '5', 'd', 'h', '3']
['4', '5', '3']
复制代码

2、贪婪匹配

贪婪匹配:在满足匹配时,匹配尽可能长的字符串,默认情况下,采用贪婪匹配

复制代码
string pattern1 = @"a.*c";   // greedy match 
Regex regex = new Regex(pattern1);
regex.Match("abcabc"); // return "abcabc"
非贪婪匹配:在满足匹配时,匹配尽可能短的字符串,使用?来表示非贪婪匹配

string pattern1 = @"a.*?c";   // non-greedy match 
Regex regex = new Regex(pattern1);
regex.Match("abcabc"); // return "abc"
复制代码

几个常用的非贪婪匹配Pattern

*? 重复任意次,但尽可能少重复
+? 重复1次或更多次,但尽可能少重复
?? 重复0次或1次,但尽可能少重复
{n,m}? 重复n到m次,但尽可能少重复
{n,}? 重复n次以上,但尽可能少重复

.*?的用法:

复制代码
--------------------------------

. 是任意字符
* 是取 0 至 无限长度
? 是非贪婪模式。
和在一起就是 取尽量少的任意字符,一般不会这么单独写,他大多用在:
.*?a

就是取前面任意长度的字符,到第一个 a 出现
复制代码

3、re模块下的常用方法

复制代码
import re

re.findall('a','alvin yuan')    #返回所有满足匹配条件的结果,放在列表里

re.search('a','alvin yuan').group()  

      #函数会在字符串内查找模式匹配,只到找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以
      # 通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。
 
re.match('a','abc').group()     #同search,不过尽在字符串开始处进行匹配
 

ret=re.split('[ab]','abcd')     #先按'a'分割得到''和'bcd',在对''和'bcd'分别按'b'分割

print(ret)#['', '', 'cd']
 

ret=re.sub('\d','abc','alvin5yuan6',1)

ret=re.subn('\d','abc','alvin5yuan6')



obj=re.compile('\d{3}')
ret=obj.search('abc123eeee')
print(ret.group())#123


import re
ret=re.finditer('\d','ds3sy4784a')
print(ret)        #<callable_iterator object at 0x10195f940>
 
print(next(ret).group())
print(next(ret).group())
复制代码

注意:

findall的优先级查询:取消优先级(?:)

import re

ret=re.findall('www.(baidu|oldboy).com','www.oldboy.com')
print(ret)#['oldboy']     这是因为findall会优先把匹配结果组里内容返回,如果想要匹配结果,取消权限即可

ret=re.findall('www.(?:baidu|oldboy).com','www.oldboy.com')
print(ret)#['www.oldboy.com']

二、练习

1、 匹配一段文本中的每行的邮箱

print(re.match('^[a-zA-Z]((\w*\.[a-zA-Z0-9]*)|[a-zA-Z0-9]*)[a-zA-Z]@([a-z0-9A-Z]+\.){1,2}[a-zA-Z]{2,}$','aksjdhqo@123.123.cn').group()) 

2、 匹配一段文本中的每行的时间字符串,比如:‘1990-07-12’;

print(re.search('([12]\d{3})-((0?[1-9])|(1[0-2]))-(30|31|([12][0-9])|(0?[1-9]))','1990-12-12').group())

分别取出1年的12个月(^(0?[1-9]|1[0-2])$)

print(re.search('-((0?[1-9])|(1[0-2]))-','1990-12-31').group(1))

一个月的31天:^((0?[1-9])|((1|2)[0-9])|30|31)$

print(re.search('-(30|31|([12][0-9])|(0?[1-9]))$','1990-12-31').group(1))

3、 匹配一段文本中所有的身份证数字。

print(re.search('\d{6}(([12]\d{3})((0[1-9])|(1[0-2]))(30|31|([12][0-9])|(0[1-9])))\d{3}[\dXx]','qweqw320825195902174316').group())

4、 匹配qq号。(腾讯QQ号从10000开始) [1,9][0,9]{4,}

print(re.search('[1-9][0-9]{4,}','27440278').group())

5、 匹配一个浮点数。 ^(-?\d+)(\.\d+)?$ 或者 -?\d+\.?\d*

print(re.search(r"-?\d+\.\d*","1-2*(60+(-40.35/5)-(-4*3))").group())

6、 匹配汉字。 ^[\u4e00-\u9fa5]{0,}$

print(re.findall('[\u4e00-\u9fa5]+','你好老男孩'))

7、 匹配出所有整数

ret=re.findall(r"-?\d+\.\d*|(-?\d+)","1-2*(60+(-40.35/5)-(-4*3))")
ret.remove("")
print(ret)

 

posted @ 2018-03-05 22:19  GuoXY  阅读(142)  评论(0编辑  收藏  举报