正则表达式的基础

  正则表达式并不是Python的一部分。

  正则表达式是用于处理字符串的强大工具,拥有自己独特的语法以及一个独立的处理引擎,效率上可能不如str自带的方法,但功能十分强大。

  得益于这一点,在提供了正则表达式的语言里,正则表达式的语法都是一样的,区别只在于不同的编程语言实现支持的语法数量不同。

  就其本质而言,正则表达式(或 RE)是一种小型的、高度专业化的编程语言,(在Python中)它内嵌在Python中,并通过 re 模块实现。

元字符

元字符: . ^ $ * + ? { [ ] \ | ( )

. 匹配除了换行符外所有字符 (通配符)

content = 'Abcdefghijklmnopq'
test = re.findall(r"b.d",content)
print(test)
['bcd']

^ 以....开头

content = 'Abcdefghijklmnopq'
test = re.findall(r"^Abcd",content)
print(test)
['Abcd']

$ 以....结尾

content = 'Abcdefghijklmnopq'
test = re.findall(r"nopq$",content)
print(test)
['nopq']

* 匹配0到多次 {0, }  控制它前面的字符

content = 'Abcdefghijklmnopq'
test = re.findall(r"A.*e",content)
print(test)
['Abcde']

+ 匹配1到多次 {1, }

content = 'abcdefab111111'
test = re.findall(r"ab1+",content)
print(test)
['ab111111']

?  匹配0到1次 {0,1}

content = 'abcdefab111111'
test = re.findall(r"ab1?",content)
print(test)
['ab', 'ab1']

* +  都是按照贪婪模式进行匹配  非贪婪模式 需要在后面加个?

content = 'abcdefab111111'
test = re.findall(r"ab1+?",content)
print(test)
['ab1'] re.search(r"a(\d+?)","a2345").group() => a2 re.search(r"a(\d*?)","a2345").group() => a #如果前后均有限定条件 ?不起作用 re.search(r"a(\d*?)b","a2345b").group() => a2345b

( ) 组  作为一个整体

content = 'abcdefab111111'
test = re.findall(r"(ab1)",content)
print(test)
['ab1']

{ }  重复次数自定义

content = 'abcdefab111111'
test = re.findall(r"ab1{3,9}",content)
print(test)
['ab111111']

[ ]  字符集  表示或

      字符集里面元字符会失去意义   除了 -  \  ^ 3个元字符外

content1 = 'wwwwwabdxxxxx'
test1 = re.findall(r"a[bc]d",content1)
print(test1)
#['abd'] content2 = 'wwwwwacdxxxxx'
test2 = re.findall(r"a[bc]d",content2)
print(test2)
#['acd'] *********************************************************************** content = 'wwwwwa.xxxxx'
test = re.findall(r"a[.]x",content)
print(test)
#['a.x'] content = 'wwwww1234xxxxx'
test = re.findall(r"[1-9]",content) #1~9的数字
print(test)
#['1', '2', '3', '4'] content = 'wwwww1234xxxxx'
test = re.findall(r"[^1-9]",content) #非1~9的数字
print(test)
#['w', 'w', 'w', 'w', 'w', 'x', 'x', 'x', 'x', 'x']

\ 作用:

  • 后面跟元字符去除特殊功能
  • 后面跟普通字符实现特殊功能
  • 引用序号对应的字组所匹配的字符串
test = re.search(r"(alex)(eric)com\2","alexericcomeric")
print(test.group())
#alexericcomeric

\d  匹配任何十进制数, [0-9]

\D  匹配任何非数字字符 [^0-9]

\s   匹配任何空白字符 [ \t\n\r\f\v ]

\S  匹配任何非空白字符 [^ \t\n\r\f\v ]

\w  匹配任何字母数字字符 [a-zA-Z0-9_]

\W 匹配任何非字母数字字符 [^a-zA-Z0-9]

\b  匹配一个单词边界,单词和空格间的位置  匹配特殊字符(不单止空格)

content = 'wwwww1234xxxxx'
test = re.findall(r"\d",content)
print(test)
# ['1', '2', '3', '4'] content = 'ww&*#$%ww1234xx'
test = re.findall(r"\D",content)
print(test)
# ['w', 'w', '&', '*', '#', '$', '%', 'w', 'w', 'x', 'x'] content = 'asdasd '
test = re.findall(r"\s",content)
print(test)
# [' ', ' ', ' '] content = ' asdasd '
test = re.findall(r"\S",content)
print(test)
# ['a', 's', 'd', 'a', 's', 'd'] content = 'abc123^&*lm-\_'
test = re.findall(r"\w",content)
print(test)
# ['a', 'b', 'c', '1', '2', '3', 'l', 'm', '_'] content = 'abc123^&*lm-\_'
test = re.findall(r"\W",content)
print(test)
# ['^', '&', '*', '-', '\\'] content = 'I like Sooooo'
test = re.findall(r"like\b",content)
print(test)
# ['like'] *******************************************
test = re.findall(r"abc\b","asdasd abc ")
test = re.findall(r"abc\b","asdasd abc*")
print(test)
# ['abc']

match()

  match()

# match,从起始位置开始匹配,匹配成功返回一个对象,未匹配成功返回None

match(pattern, string, flags=0)
# pattern: 正则模型
# string : 要匹配的字符串
# falgs : 匹配模式 # re.I(re.IGNORECASE): 忽略大小写(括号内是完整写法,下同)
# M(MULTILINE): 多行模式,改变'^'和'$'的行为
# S(DOTALL): 点任意匹配模式,改变'.'的行为 使 . 匹配包括换行在内的所有字符
# L(LOCALE): 使预定字符类 \w \W \b \B \s \S 取决于当前区域设定
# U(UNICODE): 使预定字符类 \w \W \b \B \s \S \d \D 取决于unicode定义的字符属性
# X(VERBOSE): 详细模式。这个模式下正则表达式可以是多行,忽略空白字符,并可以加入注释。以下两个正则表达式是等价的: ************************************* # match对象的方法 .group() 获取匹配到的所有结果
.groups() 获取模型中匹配到的分组结果
.groupdict() 获取模型中匹配到的分组中所有执行了key的组
.group()    返回被RE匹配的字符串 可以加参数group(1) 组号
.start() 返回匹配开始的位置
.end()      返回匹配结束的位置
.span() 返回一个元组包含的匹配的位置
# 无分组
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的组

demo

search()

  search()

# search 匹配成功有结果,返回match对象
# 查看返回结果用.group()
# search,浏览整个字符串去匹配第一个,未匹配成功返回None
# search(pattern, string, flags=0)
# 无分组

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的组

demo

findall()

  findall()

# 优先取组里内容返回!
# findall,获取非重复的匹配列表;如果有一个组则以列表形式返回,且每一个匹配均是字符串;如果模型中有多个组,则以列表形式返回,且每一个匹配均是元祖;
# 空的匹配也会包含在结果中
# findall(pattern, string, flags=0) data = re.findall("\d+\w\d+",'a2b3c4d5')
# ['2b3', '4d5']
# re.findall() 匹配成功一个后,从匹配成功最后位置开始下一次查找 # 空的匹配也会包含在结果中
data = re.findall("",'a2')
print(data)
# ['', '', ''] *********************************** #有几个括号就取几次 data = re.findall(r'(\dasd)*','1asd2asdp3asd3434')
print(data)
# ['2asd', '', '3asd', '', '', '', '', '']
# 贪婪匹配 第一段取到1asd2asd 但最后返回 2asd 取最后一个! 如下:
a= "alex"
data = re.findall(r'(\w)(\w)(\w)(\w)',a)
print(data)
# [('a', 'l', 'e', 'x')] data = re.findall(r'(\w){4}',a)
print(data)
# ['x'] => 只是执行了4次,返回还是按一个括号算,取最后匹配的一项 *********************************** test = re.findall("www.(baidu|laonanhai).com","asdsa www.baidu.com")
print(test)
# ['baidu'] 添加 ?: 去掉优先权
test = re.findall("www.(?:baidu|laonanhai).com","asdsa www.baidu.com")
print(test)
# ['www.baidu.com']
# 无分组
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)
# [('bc', 'b', 'd'), ('c', '', 'd')]

demo

sub()

  sub()

# sub,替换匹配成功的指定位置字符串

sub(pattern, repl, string, count=0, flags=0)
# pattern: 正则模型
# repl : 要替换的字符串或可执行对象
# string : 要匹配的字符串
# count : 指定匹配个数
# flags : 匹配模式 test = re.sub("g.t","have","I get A, I got B , I gut C")
print(test)
#I have A, I have B , I have C ******************************************** #subn 最后还返回一个替换次数 origin = "ale4 xc 19"
data,counts = re.subn("\d+","KKK",origin)
print(data,counts)
# aleKKK xc KKK 2

compile()

  compile()

regex = re.compile(r"\w*oo\w*")
text = " JGood is ,he is cool"
data = regex.findall(text)
print(data)
#['JGood', 'cool']

split()

  split()

# split,根据正则匹配分割字符串
split(pattern, string, maxsplit=0, flags=0) # pattern: 正则模型
# string : 要匹配的字符串
# maxsplit:指定分割个数
# flags : 匹配模式 *****************************************
# 有分组情况下, 把分割的项也添加进去 origin = "hello alex bcd alex lge alex acd 19"
r1 = re.split("(alex)", origin, 1)
print(r1)
# ['hello ', 'alex', ' bcd alex lge alex acd 19'] r2 = re.split("(al(ex))", origin, 1)
print(r2)
# ['hello ', 'alex', 'ex', ' bcd alex lge alex acd 19'] ***************************************** p = re.compile(r"\d+")
test = p.split("one1two2three3four4")
print(test)
# ['one', 'two', 'three', 'four', '']
# 末尾有空字符串 => one,two2three3four4 => ['one'] two,three3four4 => .. test = re.split('[bc]','abcd')
print(test)
# ['a', '', 'd']
# 无分组
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)

demo

finditer()

  finditer()

# 返回结果为迭代对象

p = re.compile(r"\d+")
w = p.finditer(' 1 drum44ers druming , 11 ... 10 ...')
for match in w:
print(match.group(),match.span()) # 1 (1, 2)
# 44 (7, 9)
# 11 (23, 25)
# 10 (30, 32)

反斜杠的困扰

与大多数编程语言相同,正则表达式里使用"\"作为转义字符,这就可能造成反斜杠困扰。

假如你需要匹配文本中的字符"\",那么使用编程语言表示的正则表达式里将需要4个反斜杠"\\\\"

前两个和后两个分别用于在编程语言里转义成反斜杠,转换成两个反斜杠后再在正则表达式里转义成一个反斜杠。

Python里的原生字符串很好地解决了这个问题,这个例子中的正则表达式可以使用r"\\"表示。

同样,匹配一个数字的"\\d"可以写成r"\d"。有了原生字符串,你再也不用担心是不是漏写了反斜杠,写出来的表达式也更直观。

常用正则表达式

# 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_-]+)+

练习题:计算器

#!/usr/bin/env python
# -*-coding:utf-8 -*- import re # 加减运算:
def add_sub(origin):
'''
进行加减运算,按+ - 符号拆分,
:param origin: 传入的表达式
:return:
'''
data = re.split('([+-]{1})', origin)
# 预处理 把 '' 转换成 '0'
for i in range(len(data)):
if data[i].strip() == '':
data[i] = ''
# 预处理 负负得正 情况:
for i in range(len(data)):
if data[i].strip() == '' and i != 0 :
if data[i-1].strip() == '-':
data[i+1] = '+' # 计算开始:
total = 0
# flag = 0 默认加号 1为减号
flag = 0
for i in range(len(data)):
if data[i].strip() == '-':
flag = 1
continue
elif data[i].strip() == '+':
flag = 0
continue
elif flag == 0 :
total += float(data[i].strip()) if '.'in data[i] else int(data[i].strip())
elif flag == 1 :
total -= float(data[i].strip()) if '.'in data[i] else int(data[i].strip()) return total # 计算乘除,乘方运算:
def plus_div(origin):
'''
按前后顺序拆分,需要进行 乘除,乘方 运算的地方,获得式子,计算出结果,顶替回原来位置,循环此步骤,只剩加减法,再把只剩加减法的式子传入add_sub()计算
:param origin: 传入的表达式
:return:
'''
while True:
data = re.split('([-]?\d+\.?\d*\s*(?:[*/]|\*\*)\s*[-]?\d+\.?\d*)',origin,1)
# 判断表达式是否只剩加减运算 , 传入 add_sub() 进行加减法的计算
if len(data) ==1:
result = add_sub(data[0])
return result
break
# 判断表达式是否还包含 乘除,乘方 符号 ,如果包含,继续拆分运算,最终获得只剩加减的式子
elif len(data) ==3:
counts = data[1] # 获得匹配出的 运算符号 * / 或 **
before, content, after = data
else:
print('Error') # 判断需要进行哪种运算,
if '**' in counts:
num = counts.split('**')
left = float(num[0].strip()) if '.'in num[0] else int(num[0].strip())
right = float(num[1].strip()) if '.' in num[1] else int(num[1].strip())
total = left ** right elif '/' in counts:
num = counts.split('/')
left = float(num[0].strip()) if '.'in num[0] else int(num[0].strip())
right = float(num[1].strip()) if '.' in num[1] else int(num[1].strip())
total = left / right elif '*' in counts:
num = counts.split('*')
left = float(num[0].strip()) if '.'in num[0] else int(num[0].strip())
right = float(num[1].strip()) if '.' in num[1] else int(num[1].strip())
total = left * right # 此时只进行了表达式内的一次乘除,乘方运算, 计算结果拼接顶替原来的位置,继续循环直到只剩加减法
origin = before + str(total) + after def count(origin):
"""
1.一步一步拆分括号,每获得一次 最里层的括号表达式 ,就传入plus_div()函数 进行 该表达式的所有乘除运算,再进行加减运算,返回该表达式最终结果,
拼接回原表达式,替换回括号位置.再循环寻找下一个括号内表达式,直到所有括号的表达式计算完毕,最终只剩一条只包含单纯的乘除加减运算的表达式. :param origin: 需要计算的表达式
:return:
"""
while True:
# 拆分() 获得最里层的括号!
data = re.split('\(([^()]+)\)',origin,1)
if len(data) == 3:
before,content,after = data
result = plus_div(content) # () 里面的表达式传入 plus_div 进行计算
origin = before + str(result) + after # 把计算结果 拼接回原来括号的位置. 进行下一次括号寻找!
else:
# 当只剩一条只包含单纯的乘除加减运算的表达式时,
result = plus_div(data[0])
return result
break origin = " 6 * 2 + ( 4 -3.5 + 1 * 91 + (-1 +2) * 5 -5 ) / 2 + 2 ** 9"
result = count(origin) print('表达式: ' + origin)
print('我的计算结果 :\n' + str(result))
print('eval计算结果: \n'+ str(eval(origin)))

【Python之路】特别篇--Python正则表达式的更多相关文章

  1. Python之路(第九篇)Python文件操作

    一.文件的操作 文件句柄 = open('文件路径+文件名', '模式') 例子 f = open("test.txt","r",encoding = “utf ...

  2. 【Python之路】特别篇--Python面向对象(进阶篇)

    上一篇<Python 面向对象(初级篇)>文章介绍了面向对象基本知识: 面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用 类 是一个模板,模板中包装了多个“函数”供使 ...

  3. 【Python之路】特别篇--Python面向对象(初级篇)

    概述 面向过程:根据业务逻辑从上到下写垒代码 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可 面向对象:对函数进行分类和封装,让开发“更快更好更强...” 面向过程编程最易被初学 ...

  4. python之路基础篇

    基础篇 1.Python基础之初识python 2.Python数据类型之字符串 3.Python数据类型之列表 4.Python数据类型之元祖 5.Python数据类型之字典 6.Python Se ...

  5. python之路入门篇

    一. Python介绍 python的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,Guido开始写能够解释Python语言语法的解释器.Python这个名字,来 ...

  6. python之路第一篇

    一.python环境的搭建 1.window下环境的搭建 (1).在 https://www.python.org/downloads/ 下载自己系统所需要的python版本 (2).安装python ...

  7. python之路第二篇(基础篇)

    入门知识: 一.关于作用域: 对于变量的作用域,执行声明并在内存中存在,该变量就可以在下面的代码中使用. if 10 == 10: name = 'allen' print name 以下结论对吗? ...

  8. 【python之路1】python安装与环境变量配置

    直接搜索 Python,进入官网,找到下载,根据个人电脑操作系统下载相应的软件.小编的是windows os .下载python-2.7.9.msi 安装包  双击安装程序,进入安装步骤.在安装过程中 ...

  9. 【Python之路】特别篇--Python切片

    字符串切片操作 切片操作符是序列名后跟一个方括号,方括号中有一对可选的数字,并用冒号分割. 注意: 数是可选的,而冒号是必须的. consequence[start:end:step] 切片操作符中的 ...

随机推荐

  1. # MATLAB数据处理

    目录 MATLAB数据处理 数据归一化处理 冒号的作用(获取指定行列的数据) MATLAB数据处理 mean(A,(b)) %均值函数,b为设置对哪一维上的数据进行处理,默认为第一维(列),行为第二维 ...

  2. python中while循环打印星星的四种形状

    在控制台连续输出五行*,每一行星号数量一次递增 * ** *** **** ***** #1.定义一个行计数器 row = 1 while row <= 5: #定义一个列计数器 col = 1 ...

  3. 使用Iview时候 报:no-parsing-error Parsing error: x-invalid-end-tag 解决办法

    解决办法有两种解决办法: 1.MenuItem修改为:menu-item 2.在根目录下 .eslintrc.js 文件 rules 下添加: "vue/no-parsing-error&q ...

  4. Redis分布式锁解决抢购问题

    转:https://segmentfault.com/a/1190000011421467 废话不多说,首先分享一个业务场景-抢购.一个典型的高并发问题,所需的最关键字段就是库存,在高并发的情况下每次 ...

  5. Spring实战(六)自动装配的歧义性

    1.Spring进行自动装配时碰到的bean歧义性问题. 在进行自动装配时,只有仅有一个bean匹配所需结果时,才是可行的. 如果不仅仅一个bean能够匹配结果,例如一个接口有多个实现,这种歧义性会阻 ...

  6. 小程序setData方法使用总结

    做了一下小程序setData使用方法总结,如有错误,请不吝指出,Thanks♪(・ω・)ノ  //示例data: data:{ user:'young', obj:{ name:'蓝色蒲公英', ag ...

  7. 始终让footer在底部

    1.footer保持在页面底部 需求: 我们希望footer能在窗口最底端,但是由于页面内容太少,无法将内容区域撑开,从而在 footer 下面会留下一大块空白 第一种方法:采用 flexbox布局模 ...

  8. vue移动端立项

    步骤一:使用vue-cli模板创建新项目:vue init webpack ‘vue-test’ 点击查看 步骤二:引入SCSS npm  install sass-loader -D npm ins ...

  9. 【转】QT中添加的资源文件qrc时的路径问题小结

    @2019-06-13 [小记] QT中添加的资源文件qrc时的路径问题小结

  10. Java ==和equals的区别

    首先了解默认equals方法实现代码 public boolean equals(Object obj) { return (this == obj); } 1.== (1)对于基本数据类型的变量,& ...