python复习第15天:python正则表达式


title: python复习第15天:python正则表达式
date: 2020-04-05 23:00:24
tags:
- python
- 爬虫
categories: python复习
top: 16


python正则表达式

正则的写法

  • .(点号):表示任意一个字符,除了\n
  • [](中括号),匹配括号中列举的范围,如[0-9]代表任意单个字数,[a-z]代表任意单个小写字母
  • \d: 任意一个数字
  • \D:除了数字都可以
  • \s:表空格,tab键
  • \S:除了空格,tab键之外
  • \w:单词字符,a-z,A-Z,0-9,_
  • \W:除了字母和数字
  • *:表示前面的内容重复零次或者多次
  • +:表面前面内容至少出现一次
  • ?:表面前面的内容出现一次或者零次
  • {m, n} :出现m到n次
  • ^ :匹配字符串的开头
  • $:匹配字符串的结尾
  • ():对正则表达式的内容进行分组,从第一个括号开始
  • \A:匹配字符串开始
  • \Z:匹配字符串末尾
  • |:左右任意一个

使用大致步骤

  1. 使用compile将表示正则的字符串编译为一个pattern对象
  2. 利用Pattern对象提供的方法,对文本进行匹配,获取匹配结果
  3. 最后利用match对象提供的属性和方法后去信息,根据需要进行操作

常用匹配方法

match匹配

  • 必须从第一个字符开始就能匹配上,否则匹配失败
  • 返回的结果只有一个,并且支持group分组
import re
text = '1234aash34235235fdosdf'
p = re.compile('[0-9]*')
result = p.match(text)
print(result)
print(result.group())
print(result.span())
"""
<re.Match object; span=(0, 4), match='1234'>
输出结果
1234
(0, 4)
"""
  • 返回结构体re.Match
    • span:表示匹配的跨度,从哪里匹配,到哪里结束,左包括右边不包括
    • group:表示匹配的组,如果只有一组则直接打印内容
    • start:显示开始匹配的字符串的位置
    • end:表示结束字符串的位置
    • groups:当正则里面出现括号时搭配使用
import re
text = '1234aash34235235fdosdf'
p = re.compile('([0-9]*)')  # 这里多了一个括号
result = p.match(text)
print(result)
print(result.group())
print(result.groups())
print(result.span())
"""
<re.Match object; span=(0, 4), match='1234'>
1234
('1234',)
(0, 4)
"""

search匹配

  • 与match基本一致,也只返回一个结果
  • 但是可以不用从开头位置匹配
  • 返回一个结果,支持group分组
import re
text = 'a1234aash34235235fdosdf'
p = re.compile('[0-9]+')
result = p.search(text)
print(result)
print(result.group())
"""
<re.Match object; span=(1, 5), match='1234'>
1234
"""

findall匹配

  • 匹配所有能匹配到的结果
  • 不支持group分组,默认返回一个列表
import re
text = 'a1234aash34235235fdosdf'
p = re.compile('[0-9]+')
result = p.findall(text)
print(result)
"""
['1234', '34235235']
"""

finditer匹配

  • 匹配所有能匹配到的结果
  • 默认返回一个迭代,由re.Match迭代而成,可以通过for循环取出
  • re.Match支持group分组
import re
text = 'a1234aash34235235fdosdf'
p = re.compile('[0-9]+')
result = p.finditer(text)
print(result)
for r in result:
    print(r)
    print(r.group())
"""
<callable_iterator object at 0x7f26614d0210>
<re.Match object; span=(1, 5), match='1234'>
1234
<re.Match object; span=(9, 17), match='34235235'>
34235235
"""

sub替换

  • 可以用sub替换要匹配的字符
  • sub为批量替换,即可以替换多个位置
import re
text = 'a1234aash34235235fdosdf'
p = re.compile('[0-9]+')
result = p.sub('0', text)  # 把结果全部替换为0
print(result)
"""
a0aash0fdosdf
"""

group与groups的区别

  • group与groups都属于re.Match的内置属性
  • group用于直接显示匹配结果,而groups用于提取匹配结果中的值
  • 以提取百度网页title为例
import re
import requests
url = 'https://www.baidu.com'
headers = {
    'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko)\
     Chrome/80.0.3987.149 Safari/537.36'
}
response = requests.get(url, headers=headers)
html = response.text
p = re.compile('<title>(.*?)</title>')  # 提取title中间的值
result = p.search(html)
print(result.group())
print(result.groups())
"""
<title>百度一下,你就知道</title>
('百度一下,你就知道',)
"""
  • 可以看出,group直接把整个匹配的结果都提取出来了
  • groups只提取了匹配值中括号的部分,并且需要搭配()括号使用
  • 并且group的结果是一个字符串,而groups的结果是一个tuple
  • 如果存在多个组的时候,两个结果更不相同
import re
text = '2020-04-05'
p = re.compile('([0-9]{4})-([0-9]{2})')   # 这里分了两个组,一组提取年份,一组提取月份
result = p.search(text)
print(result)
print(result.group())  # 打印匹配值
print(result.groups())  # 打印匹配结果,返回一个tuple
print(result.group(0))  # 打印所有组,和group()一样
print(result.group(1))  # 打印第一组的匹配值
print(result.group(2))  # 打印第二组的匹配值
print(result.groups(0))  # 打印所有匹配结果,和groups一样的
  • 可以看出,group和groups里面是否加零结果都是一样的,即返回所有组

  • group可以指定返回第几组的值,相对来说更好筛选

  • groups直接返回匹配的所有值

  • 根据这里特性,我们可以重新使用group对上面的百度标题进行爬取

import re
import requests
url = 'https://www.baidu.com'
headers = {
    'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko)\
     Chrome/80.0.3987.149 Safari/537.36'
}
response = requests.get(url, headers=headers)
html = response.text
p = re.compile('<title>(.*?)</title>')  # 提取title中间的值
result = p.search(html)
print(result.group())
print(result.group(1))  # 把第1组的结果打印出来
print(result.groups())
"""
<title>百度一下,你就知道</title>
百度一下,你就知道
('百度一下,你就知道',)
"""

正则表达式修饰符

修饰符 描述
re.I 使匹配对大小写不敏感
re.L 做本地化识别(locale-aware)匹配
re.M 多行匹配,影响 ^ 和 $
re.S 使 . 匹配包括换行在内的所有字符
re.U 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B.
re.X 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。

re.I演示

  • 假设想要匹配所有字母,不区分大小写
import re
text1 = 'shdfi1234SHDFISHDI'
p = re.compile('[a-z]+', re.I)  # 不区分大小写,所有字母都匹配
result = p.findall(text1)
print(result)
"""
['shdfi', 'SHDFISHDI']
"""

re.M演示

  • 假设匹配以sh开头以2结尾的字符串
import re
text1 = 'sh22dfi12\n34SHDFIssSHDI'
p = re.compile('^sh.*2$', re.M)  # 匹配多行,即忽略回车匹配所有小写字母
p2 = re.compile('^sh.*2$')
result = p.findall(text1)
result2 = p2.findall(text1)
print(result)
print(result2)
"""
['sh22dfi12']
[]
"""
  • 可以看出,在多行模式下,一个字符串根据回车符号被拆分成两行,即有两个开头与结尾。

re.S演示

  • 假设匹配一个d..I的字符串
import re
text1 = 'sh22dfi12\n34SHDFIssSHDI'
p1 = re.compile('d.*I')
p2 = re.compile('d.*I', re.S)  # 让点号也能匹配换行符
result1 = p1.search(text1)
result2 = p2.search(text1)
print(result1)  # 目前没有匹配上
print(result2.group())  # 从下面的结果来看换行符也被匹配上了
"""
None
dfi12
34SHDFIssSHDI
"""

匹配中文

  • 匹配中文
    • [\u4e00-\u9fa5],不包括全角标点

贪婪匹配与非贪婪匹配

  • . *.*?
import re
text = '12ddd345'
# 匹配一个数字开头数字结尾的字符串
p1 = re.compile('[0-9].*[0-9]')  # 贪婪模式
p2 = re.compile('[0-9].*?[0-9]')  # 非贪婪模式
result1 = p1.search(text)
result2 = p2.search(text)
print(result1.group())
print(result2.group())
"""
12ddd345
12
"""
  • 正则表达式默认使用贪婪匹配
import re
text = u'123你好bbabd'
p1 = re.compile(u'[\u4e00-\u9fa5]{1,2}')  # 匹配一个或者两个中文
result1 = p1.search(text)
print(result1.group())  # 打印结果是匹配两个
"""
你好
"""
  • 如果使用非贪婪匹配
import re
text = u'123你好bbabd'
p1 = re.compile(u'[\u4e00-\u9fa5].*?')  # 匹配一个或者两个中文
result1 = p1.search(text)
print(result1.group())  # 打印结果是匹配一个
"""
你
"""
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,417评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,921评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,850评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,945评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,069评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,188评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,239评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,994评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,409评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,735评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,898评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,578评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,205评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,916评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,156评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,722评论 2 363
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,781评论 2 351

推荐阅读更多精彩内容

  • 搞懂Python 正则表达式用法 Python 正则表达式 正则表达式是一个特殊的字符序列,它能帮助你方便的检查一...
    厦热阅读 1,576评论 0 2
  • re模块手册 本模块提供了和Perl里的正则表达式类似的功能,不关是正则表达式本身还是被搜索的字符串,都可以...
    喜欢吃栗子阅读 3,995评论 0 13
  • 正则表达式、re模块、匹配单个字符、匹配多个字符、匹配开头结尾、匹配分组、re模块的高级用法、python贪婪和非...
    Cestine阅读 1,446评论 0 1
  • 类 !/usr/bin/python -- coding: UTF-8 -- class Employee:'所有...
    SkTj阅读 948评论 0 0
  • 飞天6711 2016.7.6 暑热天气诸事多, 北方燥热南雨沱。 水深火热遭煎熬, 大事欲来征兆多。 风雨雷电...
    闲淡山人阅读 189评论 2 5