re模块

  正则表达式使用单个字符串来描述、匹配一系列符合某个句法规则的字符串,在文本处理方面功能非常强大,也经常用作爬虫,来爬取特定内容,Python本身不支持正则,但是通过导入re模块,Python也能用正则表达式,下面就来讲一下python正则表达式的用法。正则表达式默认以单行开始匹配的

一、匹配规则

二、re的相关方法

re.findall()

findall(),可以将匹配到的结果以列表的形式返回,如果匹配不到则返回一个空列表,下面来看一下代码中的使用

import re

def re_method():
s1 = 'Hello, this is Joey'
s2 = 'The first price is $9.90 and the second price is $100'
print(re.findall(r'\w+',s1))
print(re.findall(r'\d+\.?\d*',s2)) if __name__ == '__main__':
re_method()

re.finditer()

可以将匹配到的结果生成一个迭代器

import re

def re_method4():
# finditer
s2 = 'The first price is $9.90 and the second price is $100'
i = re.finditer(r'\d+\.?\d*',s2)
for m in i:
print(m.group()) if __name__ == '__main__':
re_method4()

re.search()

search是匹配整个字符串直道匹配到一个就返回。

import re

def re_demo():
txt = 'If you puchase more than 100 sets, the price of product A is $9.90.'
m = re.search(r'(\d+).*\$(\d+\.?\d*)',txt)
print(m.groups()) if __name__ == '__main__':
re_demo()

re.match()

match从要匹配的字符串的开头开始,尝试匹配,如果字符串开始不符合正则表达式,则匹配失败,函数返回None,匹配成功的话用group取出匹配的结果

import re

def re_method():
# search vs match
s = 'abcdc'
print(re.search(r'c',s)) #search是从开头到结尾的匹配到第一个匹配的
print(re.search(r'^c', s))
print(re.match(r'c',s)) #match是开头开始匹配
print(re.match(r'.*c', s)) def re_match_object():
# match对象
s1 = 'Joey Huang'
m = re.match(r'(\w+) (\w+)',s1)
print(m.group(0,1,2))
print(m.groups()) m1 = re.match(r'\w+ (\w+)', s1)
print(m1.group(1))
print(m1.groups()) if __name__ == '__main__':
re_method()
re_match_object()

re.split()  

split能够将匹配的子串分割后返回列表

import re

def re_method1():
# split
s = 'This is Joey Huang'
print(re.split(r'\W', s)) if __name__ == '__main__':
re.method1()

re.sub()、re.subn()  

sub能将匹配到的字段用另一个字符串替换返回替换后的字符串,subn还返回替换的次数

import re

def re_method2():
# sub
s2 = 'The first price is $9.90 and the second price is $100'
print(re.sub(r'\d+\.?\d*','<number>',s2,2)) # 还能指定替换的次数 def re_method3():
# subn
s2 = 'The first price is $9.90 and the second price is $100'
print(re.subn(r'\d+\.?\d*','<price>',s2)) if __name__ == '__main__':
re_method2()
re_method3()

三、re的flags标识位

re.DOTALL

# 正则表达式默认以单行开始匹配的
import re def re_pattern_syntax():
# .表示任意单一字符
# *表示前一个字符出现>=0次
# re.DOTALL就可以匹配换行符\n,默认是以行来匹配的
print(re.match(r'.*', 'abc\nedf').group())
print('*' * 80)
print(re.match(r'.*', 'abc\nedf',re.DOTALL).group()) if __name__ == '__main__':
re_pattern_syntax()

re.MULTILINE  

# 正则表达式默认以单行开始匹配的
import re def re_pattern_syntax1():
# ^表示字符串开头(单行)
# re.MULTILINE多行匹配字符串开头
print(re.findall(r'^abc', 'abc\nedf'))
print('*' * 80)
print(re.findall(r'^abc', 'abc\nabc',re.MULTILINE)) def re_pattern_syntax2():
# $表示字符串结尾
# re.MULTILINE表示行的结束
print(re.findall(r'abc\d$', 'abc1\nabc2'))
print('*' * 80)
print(re.findall(r'abc\d$', 'abc1\nabc2',re.MULTILINE)) if __name__ == '__main__':
re_pattern_syntax1()
re_pattern_syntax2()

?非贪婪模式  

import re

def re_pattern_syntax4():
# greedy贪婪/non-greedy非贪婪,默认的是贪婪的匹配
s = '<H1>title</H1>'
print(re.match(r'<.+>', s).group()) #贪婪模式会匹配尽量多的匹配
print(re.match(r'<.+?>', s).group()) #非贪婪模式匹配尽量少的匹配
print(re.match(r'<(.+)>', s).group(1))
print(re.match(r'<(.+?)>', s).group(1)) def re_pattern_syntax5():
# {m}/{m,}/{m,n}
print(re.match(r'ab{2,4}', 'abbbbbbb').group()) #贪婪模式尽量匹配多
print(re.match(r'ab{2,4}?', 'abbbbbbb').group()) #非贪婪模式尽量匹配少
print('*' * 80) if __name__ == '__main__':
re_pattern_syntax4()
re_pattern_syntax5()

re.I/re.IGNORECASE

import re

def re_pattern_flags():
# re.I/re.IGNORECASE
print(re.match(r'(Name)\s*:\s*(\w+)','NAME : Joey',re.IGNORECASE).groups())
print('*' * 80) if __name__ == '__main__':
re_pattern_syntax_meta_char()

re.VERBOSE

import re

def re_pattern_flags1():
# re.VERBOSE此标识位可以添加注释/re.compile
s = 'the number is 20.5'
r = re.compile(r'''
\d+ # 整数部分
\.? # 小数点,可能包含也可能不包含
\d* # 小数部分,可选
''',re.VERBOSE)
print(re.search(r,s).group())
print(r.search(s).group())
print('*' * 80) if __name__ == '__main__':
re_pattern_syntax_meta_char1()

四、原生字符串、编译、分组

1、原生字符串

  细心的人会发现,我每一次在写匹配规则的话,都在前面加了一个r,为什么要这样写,下面从代码上来说明,

import re
#“\b”在ASCII 字符中代表退格键,\b”在正则表达式中代表“匹配一个单词边界”
print(re.findall("\bblow","jason blow cat")) #这里\b代表退格键,所以没有匹配到 print(re.findall("\\bblow","jason blow cat")) #用\转义后这里就匹配到了 ['blow'] print(re.findall(r"\bblow","jason blow cat")) #用原生字符串后就不需要转义了 ['blow']

你可能注意到我们在正则表达式里使用“\d”,没用原始字符串,也没出现什么问题。那是因为ASCII 里没有对应的特殊字符,所以正则表达式编译器能够知道你指的是一个十进制数字。但是我们写代码本着严谨简单的原理,最好是都写成原生字符串的格式。  

2、编译

如果一个匹配规则,我们要使用多次,我们就可以先将其编译,以后就不用每次都在去写匹配规则,下面来看一下用法

import re

def re_pattern_flags1():
# re.VERBOSE此标识位可以添加注释/re.compile
s = 'the number is 20.5'
r = re.compile(r'''
\d+ # 整数部分
\.? # 小数点,可能包含也可能不包含
\d* # 小数部分,可选
''',re.VERBOSE)
print(re.search(r,s).group())
print(r.search(s).group())
print('*' * 80) if __name__ == '__main__':
re_pattern_syntax_meta_char1()

3、分组  

  除了简单地判断是否匹配之外,正则表达式还有提取子串的强大功能。用()表示的就是要提取的分组,可以有多个组,分组的用法很多,

记住正则分组: 去已经匹配到的数据中提取数据

re.match()有无分组比较

# 无分组
r = re.match("h\w+", origin)
print(r.group()) # 获取匹配到的所有结果
print(r.groups()) # 获取模型中匹配到的分组结果
print(r.groupdict()) # 获取模型中匹配到的分组结果 # 有分组
# 为何要有分组?提取匹配成功的指定内容(先匹配成功全部正则,再匹配成功的局部内容提取出来) r = re.match("h(\w+).*(?P<name>\d)$", origin)
print(r.group()) # 获取匹配到的所有结果
print(r.groups()) # 获取模型中匹配到的分组结果
print(r.groupdict()) # 获取模型中匹配到的分组中所有执行了key的组

re.search()有无分组比较  

# 无分组

r = re.search("a\w+", origin)
print(r.group()) # 获取匹配到的所有结果
print(r.groups()) # 获取模型中匹配到的分组结果
print(r.groupdict()) # 获取模型中匹配到的分组结果 # 有分组 r = re.search("a(\w+).*(?P<name>\d)$", origin)
print(r.group()) # 获取匹配到的所有结果
print(r.groups()) # 获取模型中匹配到的分组结果
print(r.groupdict()) # 获取模型中匹配到的分组中所有执行了key的组

re.findall()有无分组比较  

# 无分组
r = re.findall("a\w+",origin)
print(r) # 有分组
origin = "hello alex bcd abcd lge acd 19"
r = re.findall("a((\w*)c)(d)", origin)
print(r)

re.split()有无分组比较

# 无分组
origin = "hello alex bcd alex lge alex acd 19"
r = re.split("alex", origin, 1)
print(r) # 有分组 origin = "hello alex bcd alex lge alex acd 19"
r1 = re.split("(alex)", origin, 1)
print(r1)
r2 = re.split("(al(ex))", origin, 1)
print(r2)

再来一些例子:

import re
print(re.findall(r'(\d+)-([a-z])','34324-dfsdfs777-hhh'))        # [('34324', 'd'), ('777', 'h')] print(re.search(r'(\d+)-([a-z])','34324-dfsdfs777-hhh').group(0)) # 34324-d 返回整体
print(re.search(r'(\d+)-([a-z])','34324-dfsdfs777-hhh').group(1)) # 34324 获取第一个组
print(re.search(r'(\d+)-([a-z])','34324-dfsdfs777-hhh').group(2)) # d 获取第二个组
print(re.search(r'(\d+)-([a-z])','34324-dfsdfs777-hhh').group(3)) # IndexError: no such group print(re.search(r"(jason)kk\1","xjasonkkjason").group())        #\1表示应用编号为1的组 jasonkkjason print(re.search(r'(\d)gg\1','2j333gg3jjj8').group()) # 3gg3 \1表示使用第一个组\d # 下面的返回None 为什么是空?而匹配不到3gg7,因为\1的不仅表示第一组,而且匹配到的内容也要和第一组匹配到的内容相同,第一组匹配到3,第二组匹配到7 不相同所以返回空
print(re.search(r'(\d)gg\1','2j333gg7jjj8')) print(re.search(r'(?P<first>\d)abc(?P=first)','1abc1')) # 1abc1 声明一个组名,使用祖名引用一个组  r=re.match('(?P<n1>h)(?P<n2>\w+)','hello,hi,help')  # 组名的另外一种用法
print(r.group())          # hello 返回匹配到的值
print(r.groups())          # ('h', 'ello')返回匹配到的分组
print(r.groupdict())          # {'n2': 'ello', 'n1': 'h'} 返回分组的结果,并且和相应的组名组成一个字典 # 分组是从已经匹配到的里面去取值
origin ="hello alex,acd,alex"
print(re.findall(r'(a)(\w+)(x)',origin)) # [('a', 'le', 'x'), ('a', 'le', 'x')]
print(re.findall(r'a\w+',origin)) # ['alex', 'acd', 'alex']
print(re.findall(r'a(\w+)',origin)) # ['lex', 'cd', 'lex']
print(re.findall(r'(a\w+)',origin)) # ['alex', 'acd', 'alex']
print(re.findall(r'(a)(\w+(e))(x)',origin)) # [('a', 'le', 'e', 'x'), ('a', 'le', 'e', 'x')] r=re.finditer(r'(a)(\w+(e))(?P<name>x)',origin)
for i in r :
print(i,i.group(),i.groupdict())
'''
[('a', 'le', 'e', 'x'), ('a', 'le', 'e', 'x')]
<_sre.SRE_Match object; span=(6, 10), match='alex'> alex {'name': 'x'}
<_sre.SRE_Match object; span=(15, 19), match='alex'> alex {'name': 'x'}
''' print(re.findall('(\w)*','alex')) # 匹配到了alex、但是4次只取最后一次即 x 真实括号只有1个
print(re.findall(r'(\w)(\w)(\w)(\w)','alex')) # [('a', 'l', 'e', 'x')] 括号出现了4次,所以4个值都取到了 origin='hello alex sss hhh kkk'
print(re.split(r'a(\w+)',origin)) # ['hello ', 'lex', ' sss hhh kkk']
print(re.split(r'a\w+',origin)) # ['hello ', ' sss hhh kkk']

练习  

检测一个IP地址,比如说192.168.1.1,下面看下代码怎么实现的

c=re.compile(r'((1\d\d|2[0-4]\d|25[0-5]|[1-9]\d|\d)\.){3}(1\d\d|2[0-4]\d|25[0-5]|[1-9]\d|\d)')
print(c.search('245.255.256.25asdsa10.11.244.10').group())      # 10.11.244.10 245.255.256.25不符合要求所以就没有匹配出来

这里来解释下上面的匹配规则,先看 (1\d\d|2[0-4]\d|25[0-5]|[1-9]\d|\d)\.),其中1\d\d表示匹配100-199的数字 | 代表或的意思,2[0-4]\d代表匹配100-249,25[0-5]代表匹配250-255,[1-9]\d|\d)代表匹配10-99和0-9,\.代表匹配一个点,{3}代表将前面的分组匹配3次,后面的一部分类似就不说明了。要匹配一个ip重要的是先理解ip每个字段的形式,然后再来写匹配规则。  

 

常用正则表达式:

IP:
^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$
手机号:
^1[3|4|5|8][0-9]\d{8}$
邮箱:
[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+

  

Python自动化运维之8、正则表达式re模块的更多相关文章

  1. Python自动化运维之19、Paramiko模块和堡垒机实战

    paramiko模块 paramiko是一个用于做远程控制的模块,使用该模块可以对远程服务器进行命令或文件操作,值得一说的是,fabric和ansible内部的远程管理就是使用的paramiko来现实 ...

  2. python自动化运维笔记3 —— dns处理模块dnspython

    1.3 DNS处理模块 dnspython是python实现的一个DNS工具包,它支持几乎所有的记录类型,可以用于查询.传输并动态更新ZONE信息,同时支持TSIG(事物签名)验证消息和EDNS0(扩 ...

  3. 【目录】Python自动化运维

    目录:Python自动化运维笔记 Python自动化运维 - day2 - 数据类型 Python自动化运维 - day3 - 函数part1 Python自动化运维 - day4 - 函数Part2 ...

  4. Day1 老男孩python自动化运维课程学习笔记

    2017年1月7日老男孩python自动化运维课程正式开课 第一天学习内容: 上午 1.python语言的基本介绍 python语言是一门解释型的语言,与1989年的圣诞节期间,吉多·范罗苏姆为了在阿 ...

  5. python自动化运维学习第一天--day1

    学习python自动化运维第一天自己总结的作业 所使用到知识:json模块,用于数据转化sys.exit 用于中断循环退出程序字符串格式化.format字典.文件打开读写with open(file, ...

  6. python自动化运维篇

    1-1 Python运维-课程简介及基础 1-2 Python运维-自动化运维脚本编写 2-1 Python自动化运维-Ansible教程-Ansible介绍 2-2 Python自动化运维-Ansi ...

  7. Python自动化运维的职业发展道路(暂定)

    Python职业发展之路 Python自动化运维工程 Python基础 Linux Shell Fabric Ansible Playbook Zabbix Saltstack Puppet Dock ...

  8. Python自动化运维:技术与最佳实践 PDF高清完整版|网盘下载内附地址提取码|

    内容简介: <Python自动化运维:技术与最佳实践>一书在中国运维领域将有“划时代”的重要意义:一方面,这是国内第一本从纵.深和实践角度探讨Python在运维领域应用的著作:一方面本书的 ...

  9. Python自动化运维 技术与最佳实践PDF高清完整版免费下载|百度云盘|Python基础教程免费电子书

    点击获取提取码:7bl4 一.内容简介 <python自动化运维:技术与最佳实践>一书在中国运维领域将有"划时代"的重要意义:一方面,这是国内第一本从纵.深和实践角度探 ...

  10. python自动化运维之CMDB篇-大米哥

    python自动化运维之CMDB篇 视频地址:复制这段内容后打开百度网盘手机App,操作更方便哦 链接:https://pan.baidu.com/s/1Oj_sglTi2P1CMjfMkYKwCQ  ...

随机推荐

  1. sql union代替or

    ---原始SQL SQL> SELECT deptno FROM emp WHERE empno = 7788 OR job = 'SALESMAN' ORDER BY 1; DEPTNO -- ...

  2. 玩转12款Linux开源机器人

    玩转12款Linux开源机器人 头条网2016-02-15 09:04 3DR Solo智能无人机发布于2015年中期.作为试图与大疆广受欢迎的Phantom系列无人机相抗衡的产品,它的双处理器运行L ...

  3. Codeforces Round #312 (Div. 2)小结

    爆炸了爆炸了...E题一个裸线段树没打完,A题wa了半天...... 爆炸了爆炸了....爆炸了爆炸了....rank270+滚粗 以后还是得多做模拟题...

  4. RMQ算法讲解

    RMQ算法 引入: 例1.题目描述 输入N个数和M次询问,每次询问一个区间[L,R],求第L个数到R个数之间的最大值.   第一种方法:大暴力之术. 但是……时间复杂度最坏会达到 $O(NM)$,一半 ...

  5. 利用powershell进行远程服务器管理(命令行模式)

    Pssession,Pssession是Windows Powershell会话的意思,一个会话,可以共享数据,提供交互式的对话,我们可以为某些命令例如Invoke-Command 制定会话来远程作业 ...

  6. Swift optional详解

    学习了一阵swift对于optional类型一直不是很了解,为此特意学习了一下,通过观看斯坦福大学的视频,将他所讲的进行了总结 optional 有两个值 1.not set (未设) 代表这个值没有 ...

  7. Android 适配

    给定字体大小适配时应按照12sp,14sp,18sp,22sp 这几种字体的大小设置,以避免字体大小混乱12sp以上大小,14sp 18sp 22sp 字体首选大小,不要使用奇数.小数,否则会造成精度 ...

  8. js怪招(摘录篇)

    利用a标签自动解析URL 很多时候我们有从一个URL中提取域名,查询关键字,变量参数值等的需要,而万万没想到可以让浏览器方便地帮我们完成这一任务而不用我们写正则去抓取.方法就在JS代码里先创建一个a标 ...

  9. 《网络编程》先进 I/O

    这部分是高级插座 I/O . 设置套接字超时报警,使用更方便的数据传输功能. 套接字 I/O 设置操作超时有三种方法: 转让 alarm 性能,制作时,它指定超时 SIGALRM 信号: 在 sele ...

  10. make文件中静态连接库在command里面的位置

    linux软件第一次调用动态连接库的时候要延迟几秒,怀疑在突然掉库的时候动态库加载耗费了时间,所以造成延时,遂改为静态库方式,原来的makefile文件是 testmac:         cp $( ...