正则表达式
为避免提示正则表达式和转义字符冲突,如
\d
,用\\d
来表示正则表达式,把\本身给转义掉
判断字符串里面是否包含某个字符串
a = 'C|C++|Java|Python|PHP|JavaScript|C#|Ruby|Swift'
方法一:
print(a.index('C++'))
方法二:
print('C++' in a)
方法三:正则表达式
使用正则表达式要通过re模块
re.findall函数
:字符串查找
import re
a = 'C|C++|Java|Python|PHP|JavaScript|C#|Ruby|Swift'
r = re.findall('Python', a)
print(r)
#输出:['Python'] ----- 是一个列表
问题:用正则表达式提取出下面字符串中所有数字
import re
a = 'C1C++4Java7Python0PHP4JavaScript3C#8Ruby9Swift'
r = re.findall('\d+', a)
#正则表达式中 '\d'表示数字
print(r)
#输出:['1', '4', '7', '0', '4', '3', '8', '9']
字符集
- 只能输出一个字符
\d
表示数字,[0-9]
\D
表示字母,[A-Za-z]
\w
表示数字和字母(无论大小写)以及下划线_(不包括其他符号)[A-Za-z0-9_]
\W
表示符号(空格
,&
,\n
,等其他符号)(不包括下划线
)
\s
表示空白字符(空格,制表符,换行符)[\t\n\r\f\v]
\S
表示非空白字符
.
点,表示除换行符\n
之外其他所有字符
例1:要提取出下面字符串中的acc
,aec
import re
a = 'abc,acc,adc,aec,afc,agc'
r = re.findall('a[ce]c', a)
#元字符[],字符集,出现在[]里的字符是'或'的关系
print(r)
输出:['acc', 'aec']
例2:要提取出下面字符串中非的acc
,aec
的其他字符
import re
a = 'abc,acc,adc,aec,afc,agc'
r = re.findall('a[^ce]c', a) #?元字符[^ce]表示非c和e的其他字符
print(r)
#输出:['abc', 'adc', 'afc', 'agc']
例3:要提取出下面字符串中acc
,adc
,aec
,afc
这几个中间连续的字符
import re
a = ‘abc,acc,adc,aec,afc,agc’
r = re.findall(‘a[c-f]c’, a) #?元字符[c-f]表示c到f中间所有字符
print®
#输出:[‘acc’, ‘adc’, ‘aec’, ‘afc’]
数量词
1.用{n}
表示匹配前一个字符n次,{n,}
表示匹配前一个字符n次以上,{n,m}
表示匹配前一个字符n到m次
- 字符集只能以一个字符为元素进行输出
例:
import re
a = 'abc,acc,adc'
r = re.findall('[a-z]',a)
print(r)
#输出:['a', 'b', 'c', 'a', 'c', 'c', 'a', 'd', 'c']
用数量词
{numb}
输出固定数量长度的单词为一个元素的列表
例:
import re
a = 'abc,acc,adc,aec,afc,agc'
r = re.findall('[a-z]{3}', a) #?元字符{3}表示匹配前一个字符3次
print(r)
#输出:['abc', 'acc', 'adc', 'aec', 'afc', 'agc']
如果要输出长度不一的单词为一个元素的列表呢
2.用{numb1,numb2}
输出长度不一的单词为一个元素的列表
import re
a = 'abcd,acc,ac,apple,afc'
r = re.findall('[a-z]{3,5}', a) #?{3,5}表示表示匹配前一个字符3-5次
print(r)
#输出:['abcd', 'acc', 'ac', 'apples', 'afc']
思考:匹配3-5次为什么abcd不按照3个单词为一组输出,而是优先输出4个单词呢?
贪婪与非贪婪
默认情况下python以贪婪模式匹配字符串,也就是尽可能多的匹配字符串
非贪婪的模式:
{numb}?
------ 在数量词的后面加一个?
r = re.findall('[a-z]{3,5}?', a)
#输出:['abc', 'acc', 'app','les', 'afc'] ------ 注意输出了'les'
3.用’+'输出长度不一的满足条件的所有元素
例:
import re
a = 'abcd,acc,ac,apple,afc'
r = re.findall('[a-z]+', a) #元字符+表示匹配前一个字符1次以上
print(r)
#输出:['abcd', 'acc', 'ac', 'apple', 'afc']
4.*
:匹配前一个字符0次或无限多次
例:
import re
a = 'pytho1python2pythonn3'
r = re.findall('python*', a) #元字符*表示匹配前一个字符0次或无限多次
print(r)
#输出:['pytho', 'python', 'pythonn']
#注意结果匹配'n'0次或无限多次
5.?
:匹配前一个字符0次或1次
例:
import re
a = 'pytho1python2pythonn3'
r = re.findall('python?', a)
print(r)
#输出:['pytho', 'python', 'python']
#注意结果匹配'n'0次或1次
?号经常用于去重的操作 注意区别于非贪婪模式的?
边界匹配符
例:
import re
qq = '100000001'
#如果想要输出4~8位的qq号,用前面的数量词行不行呢
r = re.findall('\\d{4,8}', qq)
print(r)
#输出:['10000000']
#结果并不符合,qq号是100000001,九位,应该剔除在外,但是输出了前八位
用边界匹配符解决
1.用
^
匹配字符串的开头
2.用$
匹配字符串的结尾
import re
qq = '100000001'
r = re.findall('^\\d{4,8}$', qq)
#一前一后就可以匹配完整的字符串
print(r)
#现在就什么不会输出前几位了,会把字符串当作一个整体来看,不会拆开来了
组
- 用
()
分组
例:
import re
a = 'PythonPythonPythonPythonPython'
现在要求判断这样的字符串里面是否包含3个Python
原来的
re.findall('Python{3},a)
是匹配单个字符n
3次
可以用括号()
把前面的单词变成一个组,r = re.findall('(Python){3}', a)
,这就能匹配3个Python
注意区分于中括号[]
-----中间是’或’的关系
而圆括号()
------中间是’且’的关系
re.findall的三个参数:
(
正则表达式pattern
,字符串string
,匹配模式flags
)
匹配模式:
re.I
:忽略大小写
re.M
:多行匹配
re.S
:用’.'匹配所有字符,包括换行符
还有好多种,只列举3种
r = re.findall('(python){3}', a, re.I | re.M)
多个匹配模式可以用|
分隔
re.S
匹配模式演示:
import re
language = 'Python\nPhp\nJava\n'
r = re.findall('python.{1}', language, re.I | re.S)
#注意正则表达式里的'.'在re.S模式下,代表匹配任意字符,包括换行符
print(r)
#输出:['python\n']
区别于:
import re
language = 'Python\nPhp\nJava\n'
r = re.findall('python.{1}', language, re.I)
print(r)
#输出:[] -------因为在非re.S模式下,'.'匹配的是除了换行符以外的任意字符
re.sub函数
- 字符串查找并替换
re.sub的五个参数:
(
正则表达式pattern
,替换后的字符串repl
,原字符串string
,替换次数count
,匹配模式flags
)
例:要把Php
换成Go
import re
language = 'PythonPhpJavaPhp'
r = re.sub('Php','Go',language,0)
#count参数默认为0,表示替换将无限进行,即替换所有的Php
print(r)
#输出:PythonGoJavaGo ------注意sub函数不是以列表输出
import re
language = 'PythonPhpJavaPhp'
r = re.sub('Php','Go',language,1) #?count为1,表示只替换一次
print(r)
#输出:PythonGoJavaPhp
re.sub
第二个参数可以是一个函数 -------非常常见的一种使用方法
import re
language = 'PythonPhpJavaPhp'
def convert(value):
matched = value.group()
#直接返回value是不行的,调用group内置,返回匹配到的字符串
return '!' + matched + '!'
r = re.sub('Php',convert,language)
print(r)
#输出:Python!Php!Java!Php!
替换还有一种方式:replace内置函数(算是sub函数的简化版)
import re
language = 'PythonPhpJavaPhp'
language.replace('Php','Go')
print(language)
#报错了,因为字符串是不可变数据类型,要重新赋值才行
import re
language = 'PythonPhpJavaPhp'
language = language.replace('Php', 'Go') # ?用法:replace
print(language)
#输出:PythonGoJavaGo
把函数作为参数传递
案例一: 在以下的字符串中,找出所有数字,并把所有大于6的数字换成9,所有小于6的数字换成0
import re
a = 'P16Y351T972H168O47N'
def convert(value):
matched = value.group()
if int(matched) > 6:
return '9'
elif int(matched) == 6:
return '6'
else:
return '0'
r = re.sub('\\d', convert, a)
print(r)
#输出:P06Y000T990H069O09N
match函数与search函数
案例:
import re
a = 'P16Y351T972H168O47N'
r = re.match('\\d', a)
print(r)
r1 = re.search('\\d', a)
print(r1)
#输出:None
<re.Match object; span=(1, 2), match='1'>
因为
match函数
只匹配字符串的开始位置,第一个字符不对就直接跳过
search函数
匹配整个字符串,输出第一个符合的字符,然后停止匹配
要读取返回的结果,需要使用group
方法
print(r1.group())
#输出:1
所以findall
函数要远远比这两个函数常用
分组:group函数
案例:要输出life
和python
之间的所有字符
import re
s = 'life is short, i use python'
r =re.search('life(.*)python',s)
#可以思考一下这个正则表达式的含义,这里加不加括号都可以,因为只有一个组
print(r.group())
#输出:life is short, i use python
#不对,连life和python也一起输出了
那怎么输出中间的字符串呢? --------下面的方法在爬虫的过程很像
爬虫抓取html网页要抓取标签中间的部分
import re
s = 'life is short, i use python'
r =re.search('life(.*)python',s)
#可以思考一下这个正则表达式的含义
print(r.group(1))
#group(1)表示第一个分组,即()内的内容,()里默认是0,匹配的是正则表达式的完整结果
#输出:is short, i use
print(r.groups()) #注意是groups
#输出:(' is short, i use ')
用findall
函数抓取标签中间的部分,更简单
import re
s = 'life is short, i use python'
r =re.findall('life(.*)python',s)
print(r) #直接输出'r'就可以
#输出:[' is short, i use ']
再来一个练习:抓取life
,python
,python
中间的字符
import re
s = 'life is short, i use python, i love python'
r =re.findall('life(.*)python(.*)python',s) #?可以使用多个分组
print(r) #?直接输出'r'就可以
#输出:[(' is short, i use ', ', i love ')]
#或者search函数,print(r.group(1,2))