Python_正则表达式

正则表达式

概述

正则表达式,regular Expression 缩写为 regex, regexp ,RE等

正则表达式是处理文本极为重要的技术,可以用它实现规则进行探索和替换.

1970年unix之父ken thompson将正则表达式引入到unix中文本编辑器ed和grep命令中由此正则表达式普及开来.

学习正则表达式w3网站

正则表达式 入门_w3cschool

学习正则表达式菜鸟入口

正则表达式 – 教程 | 菜鸟教程 (runoob.com)

分类

  1. BRE

    基本正则表达式,grep.sed,vi等软件,vim具有扩展正则表达式.

  2. ERE

    拓展正则表达式,egrep(grep -e) ,sed -r等.

  3. PCRE

    几乎所有的高级语言都是PCRE的方言或者变种,python从1.6开始使用SRE生则表达式引擎,可以为是PCRE的子集,见模块re.

基本语法

元字符

metacharacter

代码说明举例
.匹配除了换行符之外的所有字符.
[abc]字符集合,只能表示一个字符位置,匹配所包含的任意字符[abc]匹配plain中的‘a’
[^abc]字符集合,只能表示一个字符位置,匹配除去集合内字符的任意字符[^abc]匹配plin中任何一个字符,不能匹配a,b,c
[a-z]字符集合,只能表示一个字符位置,匹配集合内字符任意一个字符经常使用[A-Z],[0-9]
[^a-z]字符范围,也是一个集合,表示匹配除去集合内字符的任意字符.
\b匹配单词边界\bb表示在文本中找到b开头的单词b字符.
\B不匹配单词边界t\B,包含t但是不以t结尾的单词比如write
\Bb 不以b开头且含有b的单词比如abcd
\d匹配[0-9]之间的数字,只匹配1个\d
\D\D类似 [ ^ 0 - 9 ],匹配一个非包含数字
\s匹配一个空白字符,包括换行符,制表符,空格
[ \f \r \n \t \v ]
\S匹配一个非空白字符
\w匹配[a-zA-Z0-9],包括文字\w
\W匹配 \W之外的字符

转义符

凡是在正则表达式中有特殊意义的符号,如果想要使用它的本意则需要转义

如果是反斜杠本身则需要 \\

\r \n 还是转义后代表回车和换行

重复

代码说明举例
*表示前边正则表达式重复一次或者多次e\w* 单词e后方可以有多个非空白字符
+表示前边正则表达式重复一次以上e\w+ 单词e后方至少有一个非空白字符
?表示前边正则表达式重复0此或者一次e\w? 单词e后方有一个或者0个非空白字符
{n}重复固定次数e\w{1},单词e后方只能有一个非空白字符
{n,}重复至少次数e\w{1}==e\w+
e\w{0}= e\w*
e\w{0,1} = e\w?
{n,m}重复n到m次e\w{1,10}e后方的空白字符至少1次最多10次

练习匹配电话号码 13位

\d{11}

匹配中国座机规律 前2-3位数字(-隔离)后七位数字

\d{3,4}-\d{7}

代码说明举例
x|y匹配x或者ywood took foot food
使用w|wood 或者 (w|f) ood

捕获

代码说明举例
(pattern)使用一个小括号可以代表一个子表达式,也可以叫做分组
捕获后会自动分配组好从1开始可以改变优先级
\数字匹配对应的分组(very)\1匹配very very,但是捕获的组group是very
(?:pattern)如果仅仅为了改变优先级,就不需要捕获分组了(?:w|f)ood
‘industr(?:y|ise)’ 等价
industry|industrise
(?exp)
(?’name’exp)
命名分组捕获,但是通过name访问分组
python的语法必须是(?’’exp)

断言

零宽断言

测试字符串 wood took foot food

代码说明举例
(?=exp)零宽容度正预测先行断言,
断言exp一定在匹配的右侧出现,
也就是说断言后一定跟一个exp
f(?=oo)f后边一定有oo出现
(?<=exp)零宽容度正回顾后断言
断言exp一定出现在匹配的左边出现,
也就是说前边一定有个exp前缀
(?<=f)ood、(?<=t)ook分别匹配
ood,ook,ook前一定有t出现
负向零宽断言
代码说明举例
(?!exp)零宽容度负预测先行断言
断言exp一定不会出现在右侧
也就是说断言后侧一定不是exp
\d{3}(?!\d)匹配三位数字,断言3位
数字后边一定不能是数字
foo(?!d)foo后边一定不能是d
(?<!exp)零宽容负回顾后发断言
断言exp一定不能出现在左侧也就是说
断言前边一定不能是exp
(?<!exp)ood ood的左边一定不能f
(?#comment)注释f(?=oo)(?#这个后断言不能被捕获)

注意:

断言会不会捕获?就是断言占不占分组号呢?

断言是不会占分组号的,断言如同条件只是要求匹配

分组和捕获是同一个意思.

使用正则表达式,能用简单表达就不需要使用复杂的.

贪婪和非贪婪

默认是贪婪模式,也就是说尽可能的匹配更长的字符串.

非贪婪模式很简单,再重复的符号后边加一个?,就尽可能匹配了.

代码说明举例
*?匹配任意次,但尽可能少重复
+?匹配至少一个,但尽可能少重复
??匹配1次或者0次,但尽可能少重复
{n,}?匹配至少n次,但尽可能少重复
{n,m}匹配至少n-m次,但尽可能少重复
very very happy #使用非贪婪模式 v*.y    v.*?y 匹配

引擎选项

代码说明python
ignoreCase匹配时忽略大小写re.l
re.IGNORECASE
Singleline单行模式,可以匹配所有字符 包括\nre.s
re.DOTALL
Muitline多行模式^行首$行尾re.M
re.MUITLINE
ignorepatternWhitespace忽略表达式中的空白字符,如果是Yoon给空白字符用转义 #可以用来做注释re.X
re.VERBOSE
单行模式
. 可以匹配所有字符,包括换行符
^表示整个字符串的开头字符 $表示整个字符串末尾字符

多行模式: 
. 可以匹配除了换行符之外的所有字符,多行不影响.点好
^表示行首,$表示行尾 这里表示每一行


默认模式:
默认匹配将字符串看作为一行,不能看作为多行,.号不能匹配换行符,^表示行首$表示行尾行首行尾表示整个字符串的行首行尾

默认模式和单行模式区别:
基本相同,但是单行模式.可以匹配任何字符包括换行符,^$表示字符串开头和结尾.

默认模式和多行模式的区别:
定义了行的概念,但不影响.号的行为,^$还是行首行尾.只不过多行模式可以识别换行符.

简单理解:
单行模式只影响.号行为,多行模式重新定义^$.


ps:
注意看不到换行符 \r\n.





举例:
very  very happy

my primary  key

上方可能就有\r\n
单行匹配y$ 多行匹配happy和key的y
$匹配结尾

正则习题

IP地址

匹配合法的IP地址

192.168.1.150
0.0.0.0
255.255.255.255
17.16.52.100
172.16.0.100
400.400.999.888
001.022.003.000
257.257.255.256


#答案
(?:(25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)

提取文件名

选出含有ftp的链接,且文件类型是gz或者xz的文件名

ftp://ftp.astron.com/pub/file/file-5.14.tar.gz
ftp://ftp.gmplib.org/pub/gmp-5.1.2/gmp-5.1.2.tar.xz
ftp://ftp.vim.org/pub/vim/unix/vim-7.3.tar.bz2
http://anduin.linuxfromscratch.org/sources/LFS/lfs-packages/conglomeration//iana-etc/iana-etc-2.30.tar.bz2
http://anduin.linuxfromscratch.org/sources/other/udev-lfs-205-1.tar.bz2
http://download.savannah.gnu.org/releases/libpipeline/libpipeline-1.2.4.tar.gz
http://download.savannah.gnu.org/releases/man-db/man-db-2.6.5.tar.xz
http://download.savannah.gnu.org/releases/sysvinit/sysvinit-2.88dsf.tar.bz2
http://ftp.altlinux.org/pub/people/legion/kbd/kbd-1.15.5.tar.gz
http://mirror.hust.edu.cn/gnu/autoconf/autoconf-2.69.tar.xz
http://mirror.hust.edu.cn/gnu/automake/automake-1.14.tar.xz

#答案
^ftp.*/.(?:gz|xz)

匹配邮箱地址

test@hot-mail.com
v-ip@magedu.com
web.manager@magedu.com.cn
super.user@google.com
a@w-a-com

#答案

\w.*@.*
严谨点就是
\w[\w.-]*@.*

匹配html标记

提取href中的链接url,提取文字“马哥教育”

<a href='http://www.magedu.com/index.html' target='_blank'>马哥教育</a>

#答案
.*>\w+<.*
严谨点
<a.*?>[^><].*
<a.*[^><].*

匹配URL

http://www.magedu.com/index.html
https://login.magedu.com
file:///ect/sysconfig/network

#答案
(\w+)://(\s*)
#严谨点
^(f|h)\w+://.*


匹配二代中国身份证ID

321105700101003
321105197001010030
11210020170101054X
17位数字+1位校验码组成
前6位地址码,8位出生年月,3位数字,1位校验位(0-9或X)

#答案
\w{17}(\w|x)
#严谨

python_正则表达式

python的re模块提供了正则表达式的处理能力

常量

常量说明
re.M
re.MULTILINE
多行模式
re.S
re.DOTALL
单行模式
re.l
re.IGNORECASE
忽略大小写
re.X
re.VERBOSE
忽略表达式中的空白字符

使用|位或运算开启多种选项

re.M|re.X

方法

编译

re.compile(pattern,flage=0)

设定flage,编译模式,返回正则表达式对象regex.

pattern即为正则表达式字符串,flage即为选项,正则表达式需要编译为了提高效率,编译结果回保存,下次同样使用pattern时就不用再次编译了.

单词匹配

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

regex.match(pattern[,pos[, endpos]])

match匹配从字符串头开始匹配,regex对象math方法可以重定义开始位置和解决位置,返回match对象.

re.search(pattern, string,flage=0)

regex.search(string[,pos[,endpos]])

从头开始搜索对象匹配第一个,regex对象search方法可以重设置开始位置和结束位置,返回match对象.

re.fullmatch(pattern,string,flage=0)

regex.fullmatch(string[,pos[,endpos]])

整个字符串和正则表达式匹配

import  re

s = '''bottle\nbag\nbig\napple'''
for i,c in enumerate(s,1):

    print (i-1,c,end='\n' if i%10 ==0 else '' )

print ('match' '-------------------------------')
result = re.match('b',s)
print (1,result)
result = re.match('a',s)
print (2,result)
result =re.match('^a',s,re.M)
print (3,result)
result =re.match('^a',s,re.S)
print (4,result)
regex = re.compile('a')
result = regex.match(s)
print (5,result)
result = regex.match(s,15)
print (6,result)

全文搜索

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

regex.findall(string[,pos[,endpos]])

对整个字符串,从左至右匹配,返回匹配项的列表

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

regex.findall(string[,pos[,endpos]])

对整个字符串从左至右匹配,返回所有匹配项,返回迭代器

注意每次迭代都是match对象

import  re

s = '''bottle\nbag\nbig\nable'''
for i,c in enumerate(s,1):

    print ((i-1,c),end='\n' if i%10 ==0 else '' )



result = re.findall('b',s)
print (1,result,sep='\n')
regex =re.compile('^b.*')
result = regex.findall(s)
print (2,result)
regex = re.compile('^b.*',re.M)
result = regex.findall(s,7)
print (3,result)
regex = re.compile('^b.*',re.S)
result = regex.findall(s,0,6)
print (4,result)
regex = re.compile('^b.*',re.M)
result = regex.findall(s,7,10)
print (5,result)

分别猜测我匹配的什么???

匹配替换

re.sub (pattern,replacement,string,count=0,flasg=0)

regex.sub(replacement,string ,count=0)

使用pattern对字符串string进行匹配,对匹配项使用replacement进行替换.

replacement可以是string,bytes,function

re.subn(pattern,replacement,string,count=0,flasg=0)

regex.subn(replacement,string,count=0)

同一个sub返回一个元组(new_string,number_of_subs_made)

import  re

s = '''bottle\nbag\nbig\nable'''
for i,c in enumerate(s,1):

    print ((i-1,c),end='\n' if i%10 ==0 else '' )

regex = re.compile('b\wg')
result = regex.sub('xiexie',s) #匹配多次
print (1,result)
result = regex.sub('xiexie',s,1) #匹配一次
print (2,result)


regex = re.compile('\s+')  #匹配一个或者多个空白字符,换行符,制表符
result = regex.subn('\t',s) #将空白字符,换行符,制表符替换为字符串'\t',并且显示个数
print (3,result)

需要多次练习

分组

使用小括号的pattern捕获的数据放到group中.

macth,search函数返回macth对象,findall返回字符串列表,finditer返回一个个match对象,如果pattern中使用了分组,如果有匹配的结果,会在match对象中.

如果pattern中使用了分组,如果有匹配的结果会在match中.

  1. 使用group(N)的方式返回对应分组,1到N是对应分组,0返回整个匹配的字符串,N不写缺省为0

  2. 如果使用了命名分组,可以使用group(‘name’)的方式取分组

  3. 也可以使用groups()返回所有分组

  4. 使用groupdict()返回所有命名的分组.

import gettext
import  re

s = '''bottle\nbag\nbig\nable'''
for i,c in enumerate(s,1):

    print ((i-1,c),end='\n' if i%10 ==0 else '' )



regex = re.compile('(b\w+)')
result = regex.match(s)
print (type(result))
print (1,'match',result.group(0),result.group(1),result[0],result.groups())
result = regex.search(s,15) #可以设置开始位置search
print (2,'search',result.groups())


regex  = re.compile('(b\w+)\n(?P<name1>b\w+)\n(?P<name2>b\w+)')
result = regex.match(s)
print (type(result))
print (3,'match',result.group(3),result.group(2),result.group(1))
print (4,'match',result.group(0).encode())
print (5,'match',result.group('name1'),result.group('name2'))
print (6,result.groups())
print (7,result.groupdict())
print (8,result)
print ('$' * 30 )
result = regex.findall(s)
for i in result:
    print (type(i),i)

regex = re.compile('(?P<head>b\w+)')
result = regex.finditer(s)
print ('*' * 30 )
for i in result:
    print (type(i),i,i.group(),i.group('head'),i['head'],i[0])

字符串分割

字符串的分割函数split,太难用,不能指定多个字符进行分割

re.split(pattern,string,maxsplit=0,flage=0)

split分割字符串

import gettext
import  re

s = '''bottle\nbag\nbig\nable'''
for i,c in enumerate(s,1):

    print ((i-1,c),end='\n' if i%10 ==0 else '' )




a = """
os.path.abspath(path)
normpath(join(os.getcwd(), path)).
"""

# print (re.split())
print (re.split('[\.()\s,]+',a)) #只能单行切

总结:

一般来说练习本课题需要反复练习代码,不到100行代码需要各位反复练习

import gettext
import  re

s = '''bottle\nbag\nbig\nable'''
for i,c in enumerate(s,1):

    print ((i-1,c),end='\n' if i%10 ==0 else '' )


result = re.match('b',s)
print (1,result)
result = re.match('a',s)
print (2,result)
result =re.match('^a',s,re.M)
print (3,result)
result =re.match('^a',s,re.S)
print (4,result)
regex = re.compile('a')
result = regex.match(s)
print (5,result)
result = regex.match(s,15)
print (6,result)


result = re.findall('b',s)
print (1,result,sep='\n')
regex =re.compile('^b.*')
result = regex.findall(s)
print (2,result)
regex = re.compile('^b.*',re.M)
result = regex.findall(s,7)
print (3,result)
regex = re.compile('^b.*',re.S)
result = regex.findall(s,0,6)
print (4,result)
regex = re.compile('^b.*',re.M)
result = regex.findall(s,7,10)
print (5,result)


print ('*&^%$#@@!!' * 30 )
regex = re.compile('^b\w+',re.M)
result = regex.finditer(s)
print (6,result)
r = next(result)
print (7,type(r),r)
print (8,r.start(),r.end(),s[r.start():r.end()])
print (9,type(r),r)
print (10,r.start(),r.end(),s[r.start():r.end()])

regex = re.compile('b\wg')
result = regex.sub('xiexie',s) #匹配多次
print (1,result)
result = regex.sub('xiexie',s,1) #匹配一次
print (2,result)


regex = re.compile('\s+')  #匹配一个或者多个空白字符,换行符,制表符
result = regex.subn('\t',s) #将空白字符,换行符,制表符替换为字符串'\t',并且显示个数
print (3,result)


regex = re.compile('(b\w+)')
result = regex.match(s)
print (type(result))
print (1,'match',result.group(0),result.group(1),result[0],result.groups())
result = regex.search(s,15) #可以设置开始位置search
print (2,'search',result.groups())


regex  = re.compile('(b\w+)\n(?P<name1>b\w+)\n(?P<name2>b\w+)')
result = regex.match(s)
print (type(result))
print (3,'match',result.group(3),result.group(2),result.group(1))
print (4,'match',result.group(0).encode())
print (5,'match',result.group('name1'),result.group('name2'))
print (6,result.groups())
print (7,result.groupdict())
print (8,result)
print ('$' * 30 )
result = regex.findall(s)
for i in result:
    print (type(i),i)

regex = re.compile('(?P<head>b\w+)')
result = regex.finditer(s)
print ('*' * 30 )
for i in result:
    print (type(i),i,i.group(),i.group('head'),i['head'],i[0])

a = """
os.path.abspath(path)
normpath(join(os.getcwd(), path)).
"""

# print (re.split())
print (re.split('[\.()\s,]+',a))

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值