正则表达式

正则表达式是处理字符串的强大工具,他有自己特定的语法结构

常用匹配规则

\w  匹配字母,数字及字符串
\W  匹配不是数字,字母及字符串的字符
\s  匹配任意空白字符,
\S  匹配任意非空白字符
\d  匹配任意数字
\D  匹配任意非数组的字符
\A  匹配字符串开头
\Z  匹配字符串结尾,如果存在换行,只匹配到换行前的结束字符串
\z  匹配字符串结尾,如果存在换行,同时还会匹配到换行符
\G  匹配最后匹配完成的位置
\n  匹配一个换行符
\t  匹配一个制表符
^  匹配一个字符串的开头
$  匹配一个字符串的结尾
.  匹配任意字符,除了换行符.当re.DOTAKLL标记被指定时,则可以匹配包括换行符的任意字符
[...]

 用来表示一组字符,单独列出,比如[amk]匹配a,m或者k

[^...]

不再[]中的字符, [^amk]匹配除了a,m,k之外的字符

*  匹配0个或者多个表达式
+  匹配一个或者多个表达式
?  匹配0个或一个前面正则表达式定义的片段,非贪婪方式
{n}  精确匹配n个前面的表达式
{n,m}  匹配n到m次由前面正则表达式定义的片段,贪婪方式
a|b  匹配a或者b
()  匹配括号内的表达式,也表示一个组

 

正则表达式不是python独有的,但是python的re库提供了整个正则表达式的实现

import re
content = "hello 123 4567 Word_this a Regex Demo"
result = re.match("^hello\s\d\d\d\s\d{4}\s\w{10}",content)

print(result) #<_sre.SRE_Match object; span=(0, 25), match='hello 123 4567 World_This'>

print(result.group()) #hello 123 4567 World_This

print(result.span()) #(0, 25)

match()方法会尝试从字符串的起使位置匹配正则表达式,如果匹配,返回匹配成功的结果,如果不匹配,返回None

在match()方法中,第一个参数传入正则表达式,第二个参数传入了要匹配的字符串,

打印输出结果,可以看到结果是SRE_Match对象,有两个方法:

group()方法可以输出匹配到的内容

span()方法可以输出匹配的范围,

 

匹配目标

可以使用()将想要提取的子字符串扩起来

conent = "hello world 123456789 haha"
result = re.match("^hello\s\w{5}\s(\d+)\shaha",content)

print(result) #<_sre.SRE_Match object; span=(0, 26), match='hello world 123456789 haha'
print(result.group()) #hello world 123456789 haha
print(result.group(1)) #123456789

这里我们想把字符串中的123456789提取出来,此时可以将数字部分的正则表达式用()扩起来.然后调用group(1)获取匹配结果

假如正则表达式后面还有()包括的内容,可以依此使用group(2),group(3)等来获取

 

通用匹配

刚才我们用\s表示空白字符,\w表示字母,\d表示,其实完全没有必要那么做

万能匹配:那就是.*(点星) .(点)可以匹配任意字符 *(星)代表匹配前面的字符无限次,

他们组合到一起就可以匹配任意字符了

 

贪婪与非贪婪

content = "hello world 123456789 haha"
result = re.match("^he.*(\d+).*ha$",content)

print(result) #<_sre.SRE_Match object; span=(0, 26), match='hello world 123456789 haha'>
print(result.group(1)) #9

奇怪的事情发生了,为什么只获得了9这个数字呢

在贪婪模式下 .* 会尽可能的匹配多的字符,上面的例子中,.*后面是\d+,也就是最少一个数字,因此.*就会尽可能多的匹配,只留下了一个数字

非贪婪模式的写法是.*?

content = "hello world 123456789 haha"
result = re.match("^he.*?(\d+).*?ha$",content)

print(result) #<_sre.SRE_Match object; span=(0, 26), match='hello world 123456789 haha'>

print(result.group(1)) #123456789

在做匹配的时候,字符串中间尽量使用非贪婪模式也就是用.*?来代替.*

content = "http://www.baidu.com/s?wd=python"
result = re.match("^http.*?.com.*?",content)
print(result) #<_sre.SRE_Match object; span=(0, 20), match='http://www.baidu.com'>

但这里需要注意,如果匹配的结果在字符串结尾,  .*?可能匹配不到任何内容

 

修饰符

re.I  使匹配对大小写不敏感
re.L  做本地化识别(locale-aware)匹配
re.M  多行匹配,影响^和$
re.S  使.(点)匹配包括换行在内的所用字符
re.U  根据Unicode字符集解析字符,这个标志影响\w\W\b\B
re.X  该标志通过给予你更灵活的格式以便你将正则表达式写的更易于理解
content = '''hello
123456789 world
'''
result = re.match("^he.*?(\d+).*",content)
print(result) #None

result = re.match("^he.*?(\d+).*",content,re.S)
print(result) #<_sre.SRE_Match object; span=(0, 23), match='hello \n123456789 world\n'>

 

转义匹配

当遇到用于正则匹配模式的特殊字符时,在前面加反斜线转义一下即可

content = "(百度)http://www.baidu.com"
result = re.match("\(百度\)http:\/\/www\.baidu\.com",content)

print(result) #<_sre.SRE_Match object; span=(0, 24), match='(百度)http://www.baidu.com'>

 

 

.search()方法匹配的时候会扫描整个字符串,然后返回第一个成功匹配的结果,如果没有找到,返回None

为了匹配方便,尽量使用search()方法

>>> html = '''
... <div id="songs-list">
... <h2 class="title">经典老歌</h2>
... <p class="introduction">
... 经典老歌列表
... </p>
... <ul>
... <li data-view="2">一路上有你</li>
... <li data-view="7">
... <a href="/2.mp3" singer="任贤齐">沧海一声笑</a>
... </li>
... <li data-view="4" class="active">
... <a href="/3.mp3" singer="齐秦">往事随风</a>
... </li>
... </ul>
... </div>
... '''

result = re.search('<li.*?active.*?singer="(.*?)">(.*?)</a>',html,re.S)

print(result.group(1)) #齐秦
print(result.group(2)) #往事随风

由于绝大部分html文本都包含换行符,所以尽量都需要re.S修饰符,以免出现匹配不到的情况

 

 

前面我们介绍的search()方法,可以返回匹配的第一个结果, 。 如果想要获取匹配正则表达式的所有内容,那就要借助findall()方法了

result = re.findall('<li.*?href="(.*?)"\ssinger="(.*?)">(.*?)</a>',html,re.S)

print(result) #[('/2.mp3', '任贤齐', '沧海一声笑'), ('/3.mp3', '齐秦', '往事随风')]

print(result[0]) #('/2.mp3', '任贤齐', '沧海一声笑')

print(result[1]) #('/3.mp3', '齐秦', '往事随风')

可以看到,返回的列表中的每个元素都是元组类型,我们用对应的索引依此取出即可

 

我们还可用正则表达式sub()方法来修改文本

用第二个参数,替换掉第一个参数,第三个参数,是原字符串

>>> content = '12abr1g52ds34fge56'
>>> content = re.sub('\d+','',content)
>>> print(content)
abrgdsfge
>>> 

通过上面的例子来去除数字

 

 

compile()将正则字符串编译成正则表达式对象,以便在后面的匹配中使用

import re
content1 = '2018-06-07 10:26'
content2 = '2018-06-07 10:27'
content3 = '2018-06-07 10:28'
pattern = re.compile('\d{2}:\d{2}')
result1 = re.sub(pattern, '',content1)
result2 = re.sub(pattern, '',content2)
result3 = re.sub(pattern, '',content3)
print(result1,result2,result3)

#2018-06-07  2018-06-07  2018-06-07

另外compile()还可以传入修饰符,这样在search(),findall(),等方法中就不需要额外传了,

compile()方法可以说是给正则做了表达式做了一层封装,以便我们更好的复用

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章