正则表达式
简介
1.定义
即文本的高级匹配模式,提供搜索,替换等功能。其本质是由一系列字符和特殊符号构成的字串,这个字串即正则表达式。
2 原理
通过普通字符和有特定含义的字符,来组成字符串,用以描述一定的字符串规则,比如:重复,位置等,来表达某类特定的字符串,进而匹配。
元字符
普通字符
匹配每一个对应的字符
注: python中正则表达式可以匹配中文
re.findall('ab',"abcdefabcd")
Out: ['ab', 'ab']
或关系 |
· 匹配规则,匹配|两边的正则表达式
In : re.findall('com|cn',"www.baidu.com/www.tmooc.cn")
Out: ['com', 'cn']
匹配字符集 [ 字符集 ]
· 匹配规则: 匹配字符集中的任意一个字符,注意在[ ] 中的元素是或的关系。
e.g.
In : re.findall('[aeiou]',"How are you!")
Out: ['o', 'a', 'e', 'o', 'u']
匹配字符集反集 [ ^字符集 ]
·匹配规则: 除了这个字符集以外的任意一个字符
In : re.findall('[^0-9]',"Use 007 port")
Out: ['U', 's', 'e', ' ', ' ', 'p', 'o', 'r', 't']
匹配字符串的结尾位置 $
· 匹配规则:匹配目标字符串的结尾位置
In : re.findall('Jame$',"Hi,Jame")
Out: ['Jame']
In: re.findall(r"xx$", '38x1x234x35x612x3yxxx')
Out: ['xx']
· 应用:
可以用来判断一个字符串的结尾是不是想要的值。如果不是的话结果就是一个空的列表
匹配字符的重复 * + ? {n}
*
· 匹配规则: 匹配前面的字符出现0次或多次
In : re.findall('wo*',"wooooo~~w!")
Out: ['wooooo', 'w']
+
· 匹配规则: 匹配前面的字符出现1次或多次
In : re.findall('[A-Z][a-z]+',"Hello World")
Out: ['Hello', 'World']
注意: 注意* 和 + 的区别,虽然只是0次和一次为最低下限,但是在实际使用的时候会产生不一样的效果
?
·匹配规则:匹配前面的字符一个或多次
# 匹配数字,包括正数和负数
In : re.findall('-?[0-9]+',"Jame,age:18, -26")
Out: ['18', '-26']
{n} {m,n}
匹配规则: 匹配前面的字符出现n次,或m-n次
e.g. 匹配手机号码
In : re.findall('1[0-9]{10}',"Jame:13886495728")
Out: ['13886495728']
# 匹配qq号
In : re.findall('[1-9][0-9]{5,10}',"Baron:1259296994")
Out: ['1259296994']
说明:
单独看着这几个匹配次数的元字符很简单,但是一旦合起来,搭配的方式非常灵活,如和. \w 等元字符搭配可以产生不同的效果
匹配(非)数字字符 \d \D
·匹配规则: \d匹配任意的数字字符,\D 匹配任意非数字字符
In : re.findall('\d{1,5}',"Mysql: 3306, http:80")
Out: ['3306', '80']
匹配任意(非)普通字符 \w \W
· 匹配规则: \w 匹配普通字符,\W 匹配非普通字符
· 说明: 普通字符指数字,字母,下划线,汉字。
匹配任意非空字符 \s \S
· 匹配规则: \s 匹配空字符,\S 匹配非空字符
· 说明:空字符指 空格 \r \n \t \v \f 字符
In : re.findall('\w+\s+\w+',"hello world")
Out: ['hello world']
匹配开头结尾位置 \A \Z
·匹配规则: \A 表示开头位置,\Z 表示结尾位置
注: 这个基本用不到
匹配(非)单词的边界位置 \b \B
·匹配规则: \b 表示单词边界 \B表示非单词边界
In : re.findall(r'\bis\b',"This is a test.")
Out: ['is']
总结
这些元字符的熟练运用我认为是正则表达式的基本也是关键,若熟练掌握则此法修成。
类别 | 元字符 |
---|---|
匹配字符 | . […] [^…] \d \D \w \W \s \S |
匹配重复 | * + ? {n} {m,n} |
匹配位置 | ^ $ \A \Z \b \B |
其他 | | () \ |
贪婪模式和非贪婪模式
- 定义
贪婪模式: 默认情况下,匹配重复的元字符总是尽可能多的向后匹配内容。比如: * + ? {m,n}
非贪婪模式(懒惰模式): 让匹配重复的元字符尽可能少的向后匹配内容。
- 贪婪模式转换为非贪婪模式
- 在匹配重复元字符后加 ‘?’ 号即可
* : *?
+ : +?
? : ??
{m,n} : {m,n}?
e.g.
In : re.findall(r'\(.+?\)',"(abcd)efgh(higk)")
Out: ['(abcd)', '(higk)']
正则表示的分组
- 定义
在正则表达式中,以()建立正则表达式的内部分组,子组是正则表达式的一部分,可以作为内部整体操作对象。 - 作用
· 可以被作为整体的操作,改变元字符的操作对象
e.g. 改变 +号 重复的对象
In : re.search(r'(ab)+',"ababababab").group()
Out: 'ababababab'
e.g. 改变 |号 操作对象
In : re.search(r'(王|李)\w{1,3}',"王小二").group()
Out: '王者荣耀'
· 可以通过编程语言某些接口获取匹配内容中,子组对应的内容部分
# 获取url 协议类型
re.search(r'(https|http|ftp|file)://\S+',"https://www.taobao.com").group(1)
Out:https
- 注意事项
一个正则表达式中可以包含多个子组
子组可以嵌套,但是不要重叠或者嵌套结构复杂
子组序列号一般从外到内,从左到右计数
正则表达式匹配原则
- 正确性,能够正确的匹配出目标字符串.
- 排他性,除了目标字符串之外尽可能少的匹配其他内容.
- 全面性,尽可能考虑到目标字符串的所有情况,不遗漏.
Python re模块使用
re.findall(pattern,string,flags = 0)
功能: 根据正则表达式匹配目标字符串内容
参数: pattern 正则表达式
string 目标字符串
flags 功能标志位,扩展正则表达式的匹配
返回值: 匹配到的内容列表,如果正则表达式有子组则只能获取到子组对应的内容
re.split(pattern,string,flags = 0)
功能: 使用正则表达式匹配内容,切割目标字符串
参数: pattern 正则表达式
string 目标字符串
flags 功能标志位,扩展正则表达式的匹配
返回值: 切割后的内容列表
re.sub(pattern,replace,string,max,flags = 0)
功能: 使用一个字符串替换正则表达式匹配到的内容
参数: pattern 正则表达式
replace 替换的字符串
string 目标字符串
max 最多替换几处,默认替换全部
flags 功能标志位,扩展正则表达式的匹配
返回值: 替换后的字符串
re.subn(pattern,replace,string,max,flags = 0)
功能: 使用一个字符串替换正则表达式匹配到的内容
参数: pattern 正则表达式
replace 替换的字符串
string 目标字符串
max 最多替换几处,默认替换全部
flags 功能标志位,扩展正则表达式的匹配
返回值: 替换后的字符串和替换了几处
re.finditer(pattern,string,flags = 0)
功能: 根据正则表达式匹配目标字符串内容
参数: pattern 正则表达式
string 目标字符串
flags 功能标志位,扩展正则表达式的匹配
返回值: 匹配结果的迭代器
re.fullmatch(pattern,string,flags=0)
功能:完全匹配某个目标字符串
参数:pattern 正则
string 目标字符串
返回值:匹配内容match object
re.match(pattern,string,flags=0)
功能:匹配某个目标字符串开始位置
参数:pattern 正则
string 目标字符串
返回值:匹配内容match object
re.search(pattern,string,flags=0)
功能:匹配目标字符串第一个符合内容
参数:pattern 正则
string 目标字符串
返回值:匹配内容match object
实例运用
分隔词典
把 s = "apple 苹果"按单词和意思给分开
s = "apple 苹果"
pattern = r"(\w+)"
re.findall(pattern, s)
Out: ['apple', '苹果']
用分组的方式得到对应的组合
计算器(输出计算步骤)
首先我们规定输入的运算式每个字符之间已空格隔开
第一步:我们要提取每个字符,这个可能看起来有点难但是其实就是暴力的 | 操作而已,不要怕
re.findall(’[\d.]+|(|+|-|*|/|)’, eq)
第二步: 如果有括号的话计算括号内的内容,匹配括号内的内容.
pattern = r"\(.+?\)"
list_bracket = re.findall(pattern, eq)
第三步:匹配要计算的乘法和除法
这个就比较简单了,主要是数字之间夹了一个* 或 /
eq = "1+2*3+2*5+3/5"
pattern = r"[0-9]+\*[0-9]+|[0-9]+\/[0-9]+"
re.findall(pattern, eq)
第四部: 匹配要计算的加法和减法
这个和上面基本相同
pattern = r"[0-9]+\+[0-9]+|[0-9]-[0-9]+"
re.findall(pattern, eq)
这里全部的匹配就结束了,每一步的匹配完成之后用eval()计算后,再用re.sub()替换即可
上代码
import re
class CalculateView:
def __init__(self):
self.calutating = CalculateControl()
def view(self):
print("""
*******************************************************
计算器
*******************************************************
说明:输入格式请按在每个字符之间加上空格的格式输入
输入0退出
""")
def main(self):
while True:
self.view()
eq = input("""
=-请输入-=""")
if eq == "0":
print("""
=- 谢谢使用 -=""")
break
# 调整格式
eq = self.calutating.dispose_input(eq)
# 去括号
eq1 = self.calutating.remove_bracket(eq)
# 算乘除
eq2 = self.calutating.remove_multiply_divide(eq1)
self.print_result(eq, eq1, eq2)
def print_result(self, eq, eq1, eq2):
"""
打印结果
"""
print("""
---%s"""%eq)
if eq1 != eq:
print("""
---%s""" % eq1)
print("""
---%s""" % eq2)
print("""
---%s""" % str(eval(eq2)))
# # 4 + 2 * 3 - 12 / (7 - 5 ) #
class CalculateControl:
"""
计算器的控制中心
"""
def remove_bracket(self, eq):
"""
处理括号内的计算
:param eq: 需要处理的计算式
:return: 处理后的计算式
"""
# 匹配括号内的内容
pattern = r"(?=\().*?(?<=\))"
list_bracket = re.findall(pattern, eq)
for item in list_bracket:
# 用计算好的结果替换括号内的内容
eq = re.sub(pattern, str(eval(item)), eq, 1)
return eq
def remove_multiply_divide(self, eq):
"""
去除乘除的计算
:param eq: 需要处理的计算式
:return: 处理好的计算式
"""
# 匹配乘号运算的对象和除号运算的对象
pattern = r"\d+\*\d+|\d+/\d+"
format_list = re.findall(pattern, eq)
for item in format_list:
# 用乘除后的结果替换原来的 ×*× ×/×
eq = re.sub(pattern, str(eval(item)), eq, 1)
return eq
def dispose_input(self, eq):
"""
处理输入的计算式
:param eq: 未处理的计算式
:return: 处理过的计算式,去除空格和#
"""
# 匹配输入的内容,去除#
format_list = re.findall('[\d\.]+|\(|\+|\-|\*|\/|\)', eq)
# 用生成器表达式和"".join()函数 去除原式中的空格
eq = "".join((item for item in format_list))
return eq
if __name__ == "__main__":
ca = CalculateView()
ca.main()