正则表达式

http://tool.oschina.net/regex 在线正则表达式测试

常用方法

^ 开头

$ 结尾

\s 空格

\d 数字

\d{5} 5个数字

\w 小写w 匹配字母+数字+下划线

\W 大写 W 匹配非字母、非数字、非下划线

. 匹配任意字符,除了换行符(但是在指定匹配模式 re.S的时候就可以)

* 匹配0-多个字符

+ 匹配一个或多个字符

\s*? 匹配一个可能有,可能没有的空白字符

\n 匹配一个换行符。等价于 \x0a 和 \cJ。

Jupyter Notebook

Jupyter Notebook

  1. pip install jupyter
  2. jupyter notebook 在命令行运行

re.match

尝试是字符串起始位置开始匹配的一个模式,如果匹配不成功,返回 None

re.match(pattern,string,flags=0)

最常规的匹配

import re
#引入正则表达式库

content = 'Hello 123 4567 World_This is a Regex Demo'
print(len(content))
result = re.match('^Hello\s\d\d\d\s\d{4}\s\w{10}.*Demo$',content)
# 【第一个参数是正则表达式的规则】,【第二个参数是被匹配的内容】
print(result)
#打印匹配结果信息
print(result.group())
# group 表示只打印匹配出来的结果
print(result.span())
# 输出匹配结果的范围 

结果如下:

20170912150521104423137.png

泛匹配

import re

content = 'Hello 123 4567 World_This is a Regex Demo'
print(len(content))

result = re.match('^Hello.*Demo$',content)
# 泛匹配,匹配 Hello  Demo 中间的所有内容。

print(result)
print(result.group())
print(result.span())

结果和上面的是一样的。

20170912150521104423137.png

匹配目标

import re

content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match('^Hello\s(\d+)\sWorld.*Demo$',content)
# 我们需要匹配的是1234567
# \d+ 表示匹配1个或多个数字
# () 内为需要匹配的内容
print(result)
print(result.group(1))
# group(1)表示第一个group,如果匹配规则有两个group,那第二个就是 group(2)
print(result.span())

我们需要匹配的是1234567

\d+ 表示匹配1个或多个数字

() 内为需要匹配的内容

group(1)表示第一个group,如果匹配规则有两个group,那第二个就是 group(2)

贪婪模式

import re

content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match('^He.*(\d+).*Demo$',content)
# .* 贪婪识别
print(result)
print(result.group(1))
print(result.span())

结果如下,它只匹配到到了一个7, 因为(\d+)前面的 .*会匹配尽可能多的字符,而(\d+)是需要匹配至少一个,由于前面是贪婪的,所以(\d+)就只能得到一个数字了。

20170913150527158486934.png

非贪婪模式

.*后面加一个"问号",变成 .*? 就是匹配 尽量少 的字符。

import re

content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match('^He.*?(\d+).*Demo$',content)
# .*?  非贪婪识别
print(result)
print(result.group(1))
print(result.span())

20170913150527225285618.png

这个时候结果就是1234567了 这个时候就让 (\d+) 尽量多的识别了字符

匹配模式(换行匹配)

import re

content = '''Hello 1234567 World_This
is a Regex Demo'''
#  ''' 内容'''  是换行符的意思。如过按照上面的写法是无法匹配出结果的
result = re.match('^He.*?(\d+).*Demo$',content,re.S)
# 后面的re.S (大写 S)就可以让.匹配换行符了。
print(result)
print(result.group(1))
print(result.span())

结果如下,在html里面有换行符是非常常见的。

20170913150527311772465.png

转义

import re

content = 'price is $5.00'
result = re.match('price is \$5\.00',content)
print(result)

在这里 $. 需要在前面加一个 \ 来把他们转义成字符串。 这样匹配出来的就没有问题。

20170913150527351443300.png

总结:

尽量使用泛匹配、使用括号的到匹配目标,尽量使用费贪婪模式,有换行符就用re.S

re.search

import re

content = 'Extra stings Hello 1234567 World_This is a Regex Demo Extra stings'
result = re.match('Hello.*?(\d+).*?Demo',content)
print(result)

我们从中间开始匹配,结果如下

20170913150527408738629.png

但是如果把 match 改成 search

import re

content = 'Extra stings Hello 1234567 World_This is a Regex Demo Extra stings'
result = re.search('Hello.*?(\d+).*?Demo',content)
#  把 match 改成 search
print(result)

20170913150527414821427.png

这样就匹配成功了。

为了方便,能用search 就不用 match

匹配演练

import re

html = '''<div id="songs-list">
    <h2 class="title">经典老歌</h2>
    <p class="introduction">
        经典老歌列表
    </p>
    <ul id="list" class="list-group">
        <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>
        <li data-view="6"><a href="/4.mp3" singer="beyond">光辉岁月</a></li>
        <li data-view="5"><a href="/5.mp3" singer="陈慧琳">记事本</a></li>
        <li data-view="5">
            <a href="/6.mp3" singer="邓丽君">但愿人长久</a>
        </li>
    </ul>
</div>'''

result = re.search('<li.*active.*?singer="(.*?)">(.*?)</a>',html,re.S)
if result:  # 去掉也可以
    print(result.group(1),result.group(2))

结果如下,这里匹配的结果是 带 class= active 的标签,如果去掉 active 那就会匹配第一个

任贤齐 沧海一声笑

20170913150527649332121.png

re.findall

import re

html = '''<div id="songs-list">
    <h2 class="title">经典老歌</h2>
    <p class="introduction">
        经典老歌列表
    </p>
    <ul id="list" class="list-group">
        <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>
        <li data-view="6"><a href="/4.mp3" singer="beyond">光辉岁月</a></li>
        <li data-view="5"><a href="/5.mp3" singer="陈慧琳">记事本</a></li>
        <li data-view="5">
            <a href="/6.mp3" singer="邓丽君">但愿人长久</a>
        </li>
    </ul>
</div>'''

results = re.findall('<li.*?href="(.*?)".*?singer="(.*?)">(.*?)</a>',html,re.S)
print(results)
print(type(results))
for result in results:
    print(result)
    print(result[0],result[1],result[2])

结果如下,匹配了所有的链接、歌手、歌名。

2017091315052862368488.png

匹配出歌词

import re

html = '''<div id="songs-list">
    <h2 class="title">经典老歌</h2>
    <p class="introduction">
        经典老歌列表
    </p>
    <ul id="list" class="list-group">
        <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>
        <li data-view="6"><a href="/4.mp3" singer="beyond">光辉岁月</a></li>
        <li data-view="5"><a href="/5.mp3" singer="陈慧琳">记事本</a></li>
        <li data-view="5">
            <a href="/6.mp3" singer="邓丽君">但愿人长久</a>
        </li>
    </ul>
</div>'''

results = re.findall('<li.*?>\s*?(<a.*?>)?(\w+)(</a>)?\s*?</li>',html,re.S)
# 第一个()和最后一个括号是匹配<a></a>, 因为一路上有你没有a标签,所有后面加个 ? 表示可能为0-多个。
# \s*? 表示0-多个空格
#print(results)
for result in results:
    print(result[1])

结果如下:

20170913150528706538660.png

re.sub

替换字符串中每一个匹配的子串后返回替换后的字符串。

import re

content = 'Extra stings Hello 1234567 World_This is a Regex Demo Extra stings'
content = re.sub('\d','q',content)
#如果只写 \d 就会 1-7每个数字替换一次。qqqqqqq  效果如图1
# 如果写成\d+  就会把1234567 替换成 q   效果如图2
# 第一个参数传入正则表达式,第二个参数传入要替换的内容,第三个参数传入元内容。
print(content)

20170913150528759697676.png

20170913150528775620886.png

包括内容再替换

import re

content = 'Extra stings Hello 1234567 World_This is a Regex Demo Extra stings'
content = re.sub('(\d+)',r'\1 q',content)
# 需要把替换内容放在一个小括号内,需要替换的内容要 r'\1'  r是声明一下,然后\1表示前面的括号内容,再添加其他内容 包括空格就会一起替换 之前的 1234567
print(content)

2017091315052881865135.png

替换再findall

import re

html = '''<div id="songs-list">
    <h2 class="title">经典老歌</h2>
    <p class="introduction">
        经典老歌列表
    </p>
    <ul id="list" class="list-group">
        <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>
        <li data-view="6"><a href="/4.mp3" singer="beyond">光辉岁月</a></li>
        <li data-view="5"><a href="/5.mp3" singer="陈慧琳">记事本</a></li>
        <li data-view="5">
            <a href="/6.mp3" singer="邓丽君">但愿人长久</a>
        </li>
    </ul>
</div>'''

html = re.sub('<a.*?>|</a>','',html)
#print(html)
results = re.findall('<li.*?>(.*?)</li>', html, re.S)
#print(results)
for result in results:
    print(result.strip())
    #.strip()去掉换行符

结果如下

20170913150528923225343.png

re.compile

将一个正则表达式串编译成正则对象,以便于复用该匹配模式

import re

content = '''Hello 1234567 World_This
is a Regex Demo'''

pattern = re.compile('Hello.*Demo',re.S)
result = re.match(pattern,content)
# 先写一个正则表达式规则并且赋予 pattern ,
#下次就不用写正则表达式规则了,直接在规则那输入 pattern 就调用了这个正则表达式规则。

#result = re.match('Hello.*Demo',content,re.S)
#上面个语句表达出来的意思等同这次

print(result)

实战练习

import re
import requests

content = requests.get('https://book.douban.com/').text
pattern = re.compile('<li.*?cover.*?href="(.*?)".*?title="(.*?)".*?more-meta.*?author">(.*?)</span>.*?year">(.*?)</span>.*?</li>', re.S)
results = re.findall(pattern,content)
#print(results)
for result in results:
    url,name,author,date = result
    # 每个值是一个括号
    author = re.sub('\s','',author)
    date = re.sub('\s','',date)
    # author 和date 带换行符,取消掉

    print(url,name,author,date)
    #print(url,name,author.strip(),date.strip())   #等同于上面两行的效果

结果如下

20170913150529387783569.png

Comments
Write a Comment