【Python之路】特别篇--Python正则表达式
正则表达式的基础
正则表达式并不是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正则表达式的更多相关文章
- Python之路(第九篇)Python文件操作
一.文件的操作 文件句柄 = open('文件路径+文件名', '模式') 例子 f = open("test.txt","r",encoding = “utf ...
- 【Python之路】特别篇--Python面向对象(进阶篇)
上一篇<Python 面向对象(初级篇)>文章介绍了面向对象基本知识: 面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用 类 是一个模板,模板中包装了多个“函数”供使 ...
- 【Python之路】特别篇--Python面向对象(初级篇)
概述 面向过程:根据业务逻辑从上到下写垒代码 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可 面向对象:对函数进行分类和封装,让开发“更快更好更强...” 面向过程编程最易被初学 ...
- python之路基础篇
基础篇 1.Python基础之初识python 2.Python数据类型之字符串 3.Python数据类型之列表 4.Python数据类型之元祖 5.Python数据类型之字典 6.Python Se ...
- python之路入门篇
一. Python介绍 python的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,Guido开始写能够解释Python语言语法的解释器.Python这个名字,来 ...
- python之路第一篇
一.python环境的搭建 1.window下环境的搭建 (1).在 https://www.python.org/downloads/ 下载自己系统所需要的python版本 (2).安装python ...
- python之路第二篇(基础篇)
入门知识: 一.关于作用域: 对于变量的作用域,执行声明并在内存中存在,该变量就可以在下面的代码中使用. if 10 == 10: name = 'allen' print name 以下结论对吗? ...
- 【python之路1】python安装与环境变量配置
直接搜索 Python,进入官网,找到下载,根据个人电脑操作系统下载相应的软件.小编的是windows os .下载python-2.7.9.msi 安装包 双击安装程序,进入安装步骤.在安装过程中 ...
- 【Python之路】特别篇--Python切片
字符串切片操作 切片操作符是序列名后跟一个方括号,方括号中有一对可选的数字,并用冒号分割. 注意: 数是可选的,而冒号是必须的. consequence[start:end:step] 切片操作符中的 ...
随机推荐
- php exec执行不等待返回结果
windows中:pclose(popen("start php.exe test.php","r"));lnuix中: pclose(popen(" ...
- python中的类变量和对象变量,以及传值传引用的探究
http://www.cnblogs.com/gtarcoder/p/5005897.html http://www.cnblogs.com/mexh/p/9967811.html
- Jmeter安装及配置(含JDK安装)
(一)java环境配置1.官网下载64位的jdkhttp://www.oracle.com/technetwork/java/javase/downloads/index.html 2.环境变量设置变 ...
- Java Web ActiveMQ与WebService的异同
Webservice 和MQ(MessageQueue)都是解决跨平台通信的常用手段 一.WebService:用来远程调用服务,达到打通系统.服务复用的目的.是SOA系统架构——面向服务架构的体现. ...
- sql lesson21homework
2017-08-15 18:03:17 mysql> show databases;+--------------------+| Database |+---------- ...
- C# 常用类库说明
Array类 用括号声明数组是C#中使用Array类的记号.在后台使用C#语法,会创建一个派生于抽象基类Array的新类.这样,就可以使用Array类为每个C#数组定义的方法和属性了. Array类实 ...
- shell、bash、terminal和kernel之间的关系
shell.bash.terminal和kernel之间的关系 本文是<鸟哥的Linux私房菜>的学习笔记 什么是kernel kernel的中文是"操作系统核心",主 ...
- Windows Class Styles
CS_VREDRAW:当窗口水平方向的宽度变化时重绘整个窗口 CS_HREDRAW:当窗口垂直方向的宽度变化时重绘整个窗口 CS_DBLCLKS:指针在属于此类的窗体内部,并且用户双击时,收到一个双击 ...
- 查询SQL Server版本号
一.查看SQL Server 2005版本号 SELECT @@VERSION 显示以下信息: Microsoft SQL Server 2005 - 9.00.3042.00 (Intel X86) ...
- vue事件处理机制
<button @click="handleAdd1()">add1</button> <button @click="handleAdd2 ...