总结--常用正则表达式符号
'.' 默认匹配除\n之外的任意一个字符,若指定flag DOTALL,则匹配任意字符,包括换行
'^' 匹配字符开头,若指定flags MULTILINE,这种也可以匹配上(r"^a","\nabc\neee",flags=re.MULTILINE)
'$' 匹配字符结尾,或e.search("foo$","bfoo\nsdfsf",flags=re.MULTILINE).group()也可以
'*' 匹配*号前的字符0次或多次,re.findall("ab*","cabb3abcbbac") 结果为['abb', 'ab', 'a']
'+' 匹配前一个字符1次或多次,re.findall("ab+","ab+cd+abb+bba") 结果['ab', 'abb']
'?' 匹配前一个字符1次或0次
'{m}' 匹配前一个字符m次
'{n,m}' 匹配前一个字符n到m次,re.findall("ab{1,3}","abb abc abbcbbb") 结果'abb', 'ab', 'abb']
'|' 匹配|左或|右的字符,re.search("abc|ABC","ABCBabcCD").group() 结果'ABC'
'(...)' 分组匹配,re.search("(abc){2}a(123|456)c", "abcabca456c").group() 结果 abcabca456c
'\A' 只从字符开头匹配,re.search("\Aabc","alexabc") 是匹配不到的
'\Z' 匹配字符结尾,同$
'\d' 匹配数字0-9
'\D' 匹配非数字
'\w' 匹配[A-Za-z0-9]
'\W' 匹配非[A-Za-z0-9]
's' 匹配空白字符、\t、\n、\r , re.search("\s+","ab\tc1\n3").group() 结果 '\t'
'(?P<name>...)' 分组匹配
re.search("(?P<province>[0-9]{4})(?P<city>[0-9]{2})(?P<birthday>[0-9]{4})","371481199306143242").groupdict("city")
结果{'province': '3714', 'city': '81', 'birthday': '1993'}
- 总结--最常用的匹配语法
re.match 从头开始匹配
re.search 匹配包含
re.findall 把所有匹配到的字符放到以列表中的元素返回
re.splitall 以匹配到的字符当做列表分隔符
re.sub 匹配字符并替换
- Python中字符串前面加上 r 表示原生字符串
在Python的string前面加上‘r’, 是为了告诉编译器这个string是个raw string,
不要转意backslash '\' 。
例如,\n 在raw string中,是两个字符,\和n, 而不会转意为换行符。
由于正则表达式和 \ 会有冲突,因此,当一个字符串使用了正则表达式后,最好在前面加上'r'。
- 反斜杠的困扰
与大多数编程语言相同,正则表达式里使用"\"作为转义字符,这就可能造成反斜杠困扰。假如你需要匹配文本中的字符"\",那么使用编程语言表示的正则表达式里将需要4个反斜杠"\\\\":前两个和后两个分别用于在编程语言里转义成反斜杠,转换成两个反斜杠后再在正则表达式里转义成一个反斜杠。Python里的原生字符串很好地解决了这个问题,这个例子中的正则表达式可以使用r"\\"表示。同样,匹配一个数字的"\\d"可以写成r"\d"。有了原生字符串,你再也不用担心是不是漏写了反斜杠,写出来的表达式也更直观。
- 总结--最常用的几个匹配模式
re.I(re.IGNORECASE): 忽略大小写(括号内是完整写法,下同)
M(MULTILINE): 多行模式,改变'^'和'$'的行为
S(DOTALL): 点任意匹配模式,改变'.'的行为
正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配。
Python 自1.5版本起增加了re 模块,它提供 Perl 风格的正则表达式模式。
- re 模块--使 Python 语言拥有全部的正则表达式功能。
- compile 函数--根据一个模式字符串和可选的标志参数生成一个正则表达式对象。该对象拥有一系列方法用于正则表达式匹配和替换。
- re 模块--也提供了与这些方法功能完全一致的函数,这些函数使用一个模式字符串做为它们的第一个参数。
本文主要介绍Python中常用的正则表达式处理函数。
re.match函数
- re.match 尝试从字符串的开始匹配一个模式。
- 函数语法:
re.match(pattern, string, flags=0)
- 函数参数说明:
参数 | 描述 |
pattern | 匹配的正则表达式 |
string | 要匹配的字符串。 |
flags | 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。 |
- 匹配成功re.match方法返回一个匹配的对象,否则返回None。
- 我们可以使用group(num) 或 groups() 匹配对象函数来获取匹配表达式。
匹配对象方法 | 描述 |
group(num=0) | 匹配的整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。 |
groups() | 返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。 |
实例:
#!/usr/bin/python
import re
line = "Cats are smarter than dogs"
matchObj = re.match(r'(.*) are (.*?) .*', line, re.M | re.I)
if matchObj:
print ("matchObj.group() : ", matchObj.group())
print ("matchObj.group(1) : ", matchObj.group(1))
print ("matchObj.group(2) : ", matchObj.group(2))
else:
print ("No match!!")
以上实例执行结果如下:
matchObj.group() : Cats are smarter than dogs
matchObj.group(1) : Cats
matchObj.group(2) : smarter
re.search方法
- re.match 尝试从字符串的开始匹配一个模式。
- 函数语法:
re.search(pattern, string, flags=0)
- 函数参数说明:
参数 | 描述 |
pattern | 匹配的正则表达式 |
string | 要匹配的字符串。 |
flags | 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。 |
- 匹配成功re.search方法方法返回一个匹配的对象,否则返回None。
- 我们可以使用group(num) 或 groups() 匹配对象函数来获取匹配表达式。
匹配对象方法 | 描述 |
group(num=0) | 匹配的整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。 |
groups() | 返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。 |
- 实例:
#!/usr/bin/python
import re
line = "Cats are smarter than dogs"
searchObj = re.search(r'(.*) are (.*?) .*', line, re.M | re.I)
if searchObj:
print ("searchObj.group() : ", searchObj.group())
print ("searchObj.group(1) : ", searchObj.group(1))
print ("searchObj.group(2) : ", searchObj.group(2))
else:
print ("No search!!")
- 以上实例执行结果如下:
searchObj.group() : Cats are smarter than dogs
searchObj.group(1) : Cats
searchObj.group(2) : smarter
re.match与re.search的区别
- re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;
- 而re.search匹配整个字符串,直到找到一个匹配。
- 实例:
#!/usr/bin/python
import re
line = "Cats are smarter than dogs";
matchObj = re.match(r'dogs', line, re.M | re.I)
if matchObj:
print ("match --> matchObj.group() : ", matchObj.group())
else:
print ("No match!!")
matchObj = re.search(r'dogs', line, re.M | re.I)
if matchObj:
print ("search --> matchObj.group() : ", matchObj.group())
else:
print ("No match!!")
- 以上实例运行结果如下:
No match!!
search --> matchObj.group() : dogs
检索和替换
- Python 的re模块提供了re.sub用于替换字符串中的匹配项。
- 语法:
re.sub(pattern, repl, string, count=0, flags=0)
- 返回的字符串是在字符串中用 RE 最左边不重复的匹配来替换。如果模式没有发现,字符将被没有改变地返回。
- 可选参数 count 是模式匹配后替换的最大次数;count 必须是非负整数。缺省值是 0 表示替换所有的匹配。
- 实例:
# !/usr/bin/python
import re
phone = "2004-959-559 # This is Phone Number"
# Delete Python-style comments
num = re.sub(r'#.*$', "", phone)
print ("Phone Num : ", num)
# Remove anything other than digits
num = re.sub(r'\D', "", phone)
print ("Phone Num : ", num)
- 以上实例执行结果如下:
Phone Num : 2004-959-559
Phone Num : 2004959559
正则表达式修饰符 - 可选标志
- 正则表达式可以包含一些可选标志修饰符来控制匹配的模式。
- 修饰符被指定为一个可选的标志。多个标志可以通过按位 OR(|) 它们来指定。
- 如 re.I | re.M 被设置成 I 和 M 标志:
修饰符 | 描述 |
re.I | 使匹配对大小写不敏感 |
re.L | 做本地化识别(locale-aware)匹配 |
re.M | 多行匹配,影响 ^ 和 $ |
re.S | 使 . 匹配包括换行在内的所有字符 |
re.U | 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B. |
re.X | 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。 |
正则表达式模式
- 模式字符串使用特殊的语法来表示一个正则表达式:
- 字母和数字表示他们自身。一个正则表达式模式中的字母和数字匹配同样的字符串。
- 多数字母和数字前加一个反斜杠时会拥有不同的含义。
- 标点符号只有被转义时才匹配自身,否则它们表示特殊的含义。
- 反斜杠本身需要使用反斜杠转义。
- 由于正则表达式通常都包含反斜杠,所以你最好使用原始字符串来表示它们。模式元素(如 r'/t',等价于'//t')匹配相应的特殊字符。
- 下表列出了正则表达式模式语法中的特殊元素。如果你使用模式的同时提供了可选的标志参数,某些模式元素的含义会改变。
正则表达式的符号与方法
常用符号:点号,星号,问号与括号(小括号)
. :匹配任意字符,换行符\n除外
* :匹配前一个字符0次或无限次
? :匹配前一个字符0次或1次
.* :贪心算法
.*? :非贪心算法
() :括号内的数据作为结果返回
常用方法:findall, search, sub
findall:匹配所有符合规律的内容,返回包含结果的列表
search:匹配并提取第一个规律的内容,返回一个正则表达式对象(object)
sub:替换符合规律的内容,返回替换后的值
表1.常用的元字符
代码 | 说明 |
. | 匹配除换行符以外的任意字符 |
\w | 匹配字母或数字或下划线或汉字 |
\s | 匹配任意的空白符 |
\d | 匹配数字 |
\b | 匹配单词的开始或结束 |
^ | 匹配字符串的开始 |
$ | 匹配字符串的结束 |
表2.常用的限定符
代码/语法 | 说明 |
* | 重复零次或更多次 |
+ | 重复一次或更多次 |
? | 重复零次或一次 |
{n} | 重复n次 |
{n,} | 重复n次或更多次 |
{n,m} | 重复n到m次 |
表3.常用的反义代码
代码/语法 | 说明 |
\W | 匹配任意不是字母,数字,下划线,汉字的字符 |
\S | 匹配任意不是空白符的字符 |
\D | 匹配任意非数字的字符 |
\B | 匹配不是单词开头或结束的位置 |
[^x] | 匹配除了x以外的任意字符 |
[^aeiou] | 匹配除了aeiou这几个字母以外的任意字符 |
表4.常用分组语法
分类 | 代码/语法 | 说明 |
捕获 | (exp) | 匹配exp,并捕获文本到自动命名的组里 |
(?<name>exp) | 匹配exp,并捕获文本到名称为name的组里,也可以写成(?'name'exp) | |
(?:exp) | 匹配exp,不捕获匹配的文本,也不给此分组分配组号 | |
零宽断言 | (?=exp) | 匹配exp前面的位置 |
(?<=exp) | 匹配exp后面的位置 | |
(?!exp) | 匹配后面跟的不是exp的位置 | |
(?<!exp) | 匹配前面不是exp的位置 | |
注释 | (?#comment) | 这种类型的分组不对正则表达式的处理产生任何影响,用于提供注释让人阅读 |
表5.懒惰限定符
代码/语法 | 说明 |
*? | 重复任意次,但尽可能少重复 |
+? | 重复1次或更多次,但尽可能少重复 |
?? | 重复0次或1次,但尽可能少重复 |
{n,m}? | 重复n到m次,但尽可能少重复 |
{n,}? | 重复n次以上,但尽可能少重复 |
1)findall
a.点号.
import re
a = 'xzx23'
b = re.findall('x.', a)
print b
输出
['xz', 'x2']
- 点
.
是一个占位符,一个.
代表一个符号
b.星号*
import re
a = 'xyxy123'
b = re.findall('x*', a)
print(b)
输出
['x', '', 'x', '', '', '', '', '']
依次匹配字符,有则显示,无则显示''
(空)。
c.问号?
import re
a = 'xy123'
b = re.findall('x?', a)
print(b)
输出
['x', '', '', '', '', '']
单独与 *
一样,前面附加其他的符号将做非贪心限制
d.贪心.*
import re
secret_code = 'ghkj08hs68xxIxxa14kgj4w314exxlovexxbvk14rgjhxxyouxxfj4286ykjhag2'
b = re.findall('xx.*xx', secret_code)
print(b)
输出
['xxIxxa14kgj4w314exxlovexxbvk14rgjhxxyouxx']
只要满足条件全部显示,贪心算法
e.非贪心.*?
import re
secret_code = 'ghkj08hs68xxIxxa14kgj4w314exxlovexxbvk14rgjhxxyouxxfj4286ykjhag2'
b = re.findall('xx.*?xx', secret_code)
print(b)
输出
['xxIxx', 'xxlovexx', 'xxyouxx']
以上只做了解,一般只用(.*?)
f.经典用法(.*?)
import re
secret_code = 'ghkj08hs68xxIxxa14kgj4w314exxlovexxbvk14rgjhxxyouxxfj4286ykjhag2'
b = re.findall('xx(.*?)xx', secret_code)
print(b)
输出
['I', 'love', 'you']
()
包围所需要的内容,括号内的内容作为结果返回,不需要的内容放在括号外面
2)re.S
import re
secret_code = '''ghkj08hs68xxIxxa14kgj4w314exxlove
xxbvk14rgjhxxyouxxfj4286ykjhag2'''
#love后有换行符
b = re.findall('xx(.*?)xx', secret_code)
print(b)
# 因为.不能匹配换行符。所以会一行为一个搜索项去找。匹配任何字符除了新的一行
输出
['I', 'bvk14rgjh']
re.S
import re
secret_code = '''ghkj08hs68xxIxxa14kgj4w314exxlove
xxbvk14rgjhxxyouxxfj4286ykjhag2'''
#love后有换行符
b = re.findall('xx(.*?)xx', secret_code, re.S)
print(b)
# re.S让.匹配所有行,包括了换行符(以\n的形式出现)
输出
['I', 'love\n', 'you']
3)search
对比search和findall的区别
search 找到一个后返回,不继续,大大提高效率
findall遍历全部,找到尽可能多的项
import re
s2 = '''ghkj08hs68xxIxx123xxlove
xxbvk14rgjhxxfj4286ykjhag2'''
b = re.search('xx(.*?)xx(.*?)xx', s2, re.S).group(1)
print(b)
c = re.search('xx(.*?)xx(.*?)xx', s2, re.S).group(2)
print(c)
d = re.search('xx(.*?)xx(.*?)xx', s2, re.S).group(3)
print(d)
输出
Traceback (most recent call last):
File "D:/WorkSpace/python/Django/test.py", line 7, in <module>
d = re.search('xx(.*?)xx(.*?)xx', s2, re.S).group(3)
IndexError: no such group
I
123
group
是按括号顺序匹配
import re
s2 = '''ghkj08hs68xxIxx123xxlovexxbvk14rgjhxxfj4286ykjhag2'''
f2 = re.findall('xx(.*?)xx123xx(.*?)xx', s2, re.S)
print (f2)
print (f2[0][1])
输出
[('I', 'love')]
love
每一个匹配项为第一级列表,括号为二级列表
4)sub
re.sub(pattern, repl, string, count=0, flags=0)
- 找到 RE 匹配的所有子串,并将其用一个不同的字符串替换。
第一个参数:pattern
pattern,表示正则中的模式字符串
第二个参数:repl
repl,就是replacement,被替换,的字符串的意思。
第三个参数:string
string,即表示要被处理,要被替换的那个string字符串。
- 第四个参数:可选参数 count 是模式匹配後替换的最大次数;count 必须是非负整数。
- 缺省值是0表示替换所有的匹配。如果无匹配,字符串将会无改变地返回。
re.subn(pattern, repl, string, count=0, flags=0)
- 与re.sub方法作用一样,但返回的是包含新字符串和替换执行次数的两元组。
import re
s = '123abcssfasdfas123'
output = re.sub('123(.*?)123', '123789123', s)
print (output)
# sub将符合条件的()内内容提换
输出
123789123
import re
inputStr = "hello 123 world 456"
replacedStr = re.sub("\d+", "222", inputStr)
print (replacedStr)
输出
hello 222 world 222
5)注意:
from re import findall, search, S
最好不要引入,因为S等容易和变量等混淆,引起歧义
6)compile用法
import re
secret_code = '''ghkj08hs68xxIxxa14kgj4w314exxlove
xxbvk14rgjhxxyouxxfj4286ykjhag2'''
pattern = 'xx(.*?)xx'
new_pattern = re.compile(pattern, re.S)
b = re.findall(new_pattern, secret_code)
print (b)
输出
['I', 'love\n', 'you']
因为findall自动调用compile方法,所以不先编译规律compile再匹配
7)匹配纯数字(\d+)
import re
a = 'dfhkgh43gfhja873y5t2167715'
b = re.findall('(\d+)', a)
print (b)
输出
['43', '873', '5', '2167715']
2.应用举例
1)用findall和search从大量文本中匹配内容
a.提取标题
import re
old_url = 'http://www.jikexueyuan.com/course/android/?pageNum=2'
total_page = 20
f = open('text.txt', 'r')
html = f.read()
f.close()
title = re.search('<title>(.*?)</title>', html, re.S).group(1)
print title
text.txt
<html>
<head>
<title>极客学院爬虫测试</title>
</head>
<body>
<div class="topic"><a href="http://jikexueyuan.com/welcome.html">欢迎参加《Python定向爬虫入门》</a>
<div class="list">
<ul>
<li><a href="http://jikexueyuan.com/1.html">这是第一条</a></li>
<li><a href="http://jikexueyuan.com/2.html">这是第二条</a></li>
<li><a href="http://jikexueyuan.com/3.html">这是第三条</a></li>
</ul>
</div>
</div>
</body>
</html>
输出
极客学院爬虫测试
b.提取网址
link = re.findall('href="(.*?)"', html, re.S)
for each in link:
print each
输出
http://jikexueyuan.com/welcome.html
http://jikexueyuan.com/1.html
http://jikexueyuan.com/2.html
http://jikexueyuan.com/3.html
c.提取文字信息
先爬大再爬小
text_fied = re.findall('<ul>(.*?)</ul>', html, re.S)[0]
the_text = re.findall('">(.*?)</a>', text_fied, re.S)
for every_text in the_text:
print every_text
2)用sub实现翻页功能
for i inrange(2, total_page+1):
new_link = re.sub('pageNum=\d+', 'pageNum=%d'%i, old_url, re.S)
print new_link
完整代码
import re
a = 'xzx23'
# . :匹配任意字符,换行符\n除外
# 点.是一个占位符,一个.代表一个符号
b = re.findall('x.', a)
print(". :匹配任意字符,换行符\\n除外:",b)
# * :匹配前一个字符0次或无限次
# 依次匹配字符,有则显示,无则显示''(空)。
c= re.findall('x*', a)
print("* :匹配前一个字符0次或无限次:",c)
# 问号?
# ? :匹配前一个字符0次或1次
# 单独与*一样,前面附加其他的符号将做非贪心限制
d= re.findall('x?', a)
print("? :匹配前一个字符0次或1次:",d)
# 贪心.*
# 只要满足条件全部显示,贪心算法
secret_code = 'ghkj08hs68xxIxxa14kgj4w314exxlovexxbvk14rgjhxxyouxxfj4286ykjhag2'
e = re.findall('xx.*xx', secret_code)
print ("贪心.*:",e)
# 非贪心.*?
secret_code = 'ghkj08hs68xxIxxa14kgj4w314exxlovexxbvk14rgjhxxyouxxfj4286ykjhag2'
f = re.findall('xx.*?xx', secret_code)
print ("非贪心.*?:",f)
# () :括号内的数据作为结果返回
# ()包围所需要的内容,括号内的内容作为结果返回,不需要的内容放在括号外面
secret_code = 'ghkj08hs68xxIxxa14kgj4w314exxlovexxbvk14rgjhxxyouxxfj4286ykjhag2'
g = re.findall('xx(.*?)xx', secret_code)
print ("非贪心.*?:",g)
# sub将符合条件的()内内容提换
# sub:替换符合规律的内容,返回替换后的值
s = '123abcssfasdfas123'
output = re.sub('123(.*?)123', '123789123', s)
print ('sub将符合条件的()内内容提换:',output)
# re.S让.匹配所有行,包括了换行符(以\n的形式出现)
# search 找到一个后返回,不继续,大大提高效率
# findall遍历全部,找到尽可能多的项
s2 = '''ghkj08hs68xxIxx123xxlove
xxbvk14rgjhxxfj4286ykjhag2'''
b = re.search('xx(.*?)xx(.*?)xx', s2, re.S)
print ('search 找到一个后返回,不继续,大大提高效率:',b)
# 输出
# < _sre.SRE_Match
# object;
# span = (10, 20), match = 'xxIxx123xx' >
# group是按括号顺序匹配
b = re.search('xx(.*?)xx(.*?)xx', s2, re.S).group(1)
print ('search 找到一个后返回,不继续,大大提高效率:',b)
# .group(3)报错
# Traceback (most recent call last):
# File "D:/WorkSpace/python/PycharmProjects/爬虫/代码/Python-master/ReDemo.py", line 61, in <module>
# b = re.search('xx(.*?)xx(.*?)xx', s2, re.S).group(3)
# IndexError: no such group
# 每一个匹配项为第一级列表,括号为二级列表
s2 = '''ghkj08hs68xxIxx123xxlovexxbvk14rgjhxxfj4286ykjhag2'''
f2 = re.findall('xx(.*?)xx123xx(.*?)xx', s2, re.S)
print ('每一个匹配项为第一级列表,括号为二级列表:',f2[0][1])
参考来源: http://code.ziqiangxuetang.com/python/python-reg-expressions.html
参考来源:http://blog.csdn.net/SkyeyesXY/article/details/50837984