正则表达式是一个特殊的字符序列,是对字符串的逻辑操作,主要是对字符串的一种过滤,用“元字符”与“普通字符”组成一个字符串规则对已知的字符串或文本过滤出自己想要的字符串。
使用正则是为了处理文本数据。如果是简单的文本处理,那使用字符串匹配就可以达到目的,但是这样每一次匹配都要单独写语句来完成,为了更加方便,需要抽象出一种规则,这就是正则表达式的由来。
1. 使用单个字符串来描述匹配一系列符合某个句法规则的字符串
2. 是对字符串操作的一种逻辑公式
3. 应用场景:处理文本和数据
4. 处理过程:一次拿出表达式和文本中的字符比较,如果每一个字符都能匹配,则匹配成功;否则匹配失败
元字符是正则表达式规则的体现。Python的正则表达式默认区分大小写。
模式 | 描述 |
---|---|
\w |
匹配字母数字及下划线 |
\W |
匹配非字母数字及下划线 |
\s |
匹配任意空白字符,等价于[\t\n\r\f] |
\S |
匹配任意非空字符 |
\d |
匹配任意数字,等价于[0-9] |
\D |
匹配任意非数字 |
\A |
匹配字符串开始 |
\Z |
匹配字符串结束,如果存在换行,只匹配到换行前的结束字符串 |
\z |
匹配字符串结束 |
\G |
匹配最后匹配完成的位置 |
\n |
匹配一个换行符 |
\t |
匹配一个制表符 |
^ |
匹配字符串的开头 |
$ |
匹配字符串的末尾 |
. |
匹配任意字符,除了换行符。当re.S(re.DOTALL)标记被指定时,则可以匹配包括换行符的任意字符 |
[...] |
用来表示一组字符,单独列出:[amk]匹配’a’、‘m’或’k’ |
[^...] |
匹配不在[]中的字符:[^abc]匹配除了a、b、c之外的字符 |
* |
匹配0个或多个的表达式 |
+ |
匹配1个或多个的表达式 |
? |
匹配0个或1个由前面的正则表达式定义的片段,非贪婪模式 |
{n} |
精确匹配n个前面的表达式 |
{n,m} |
匹配n到m次由前面的正则表达式定义的片段,贪婪模式 |
a|b |
匹配a或b |
() |
匹配括号内的表达式,也表示一个组 |
*? +? ?? |
匹配模式为非贪婪匹配 |
\ |
引用编号为num的分组匹配到的字符串 |
(?P |
分组取一个别名为name |
(?P=name) |
引用别名为name的分组匹配字符串 |
字符集:[...]
,用来匹配一组字符。
import re
a = 'abc, acc, adc, aec, afc, agc'
r = re.findall('a[cf]c', a) #匹配中间字符是c或f的字符串
s = re.findall('a[^cf]c', a) #匹配中间字符不是c或f的字符串
print(r)
print(s)
['acc', 'afc'] #结果
['abc', 'adc', 'aec', 'agc']
概括字符集:\d
、\D
、\w
、\W
、\s
、\S
。
import re
a = 'python 1111java&6\n78php'
r = re.findall('\w', a) #匹配字母数字及下划线
s = re.findall('\W', a) #匹配非字母数字及下划线
print(r)
print(s)
['p', 'y', 't', 'h', 'o', 'n', '1', '1', '1', '1', 'j', 'a', 'v', 'a', '6', '7', '8', 'p', 'h', 'p'] #结果
[' ', '&', '\n']
可以看出,字符集及概括字符集都只能匹配单个的字符,所以结果都是单个字符。概括字符集可以用字符集表示。
数量词:*
、+
、?
、{n}
、{n,m}
。
{n}
用来精确匹配n个前面的表达式,{n,m}
以贪婪模式匹配n到m次由前面的正则表达式定义的片段,{n,m}?
以非贪婪模式匹配n到m次由前面的正则表达式定义的片段。
import re
a = 'python 1111java&6\n78php'
r = re.findall('[a-z]{3}', a) #匹配3个字母组成的字符串
s = re.findall('[a-z]{3,6}', a) #匹配3到6个字母组成的字符串
t = re.findall('[a-z]{3,6}?', a) #以非贪婪模式匹配3到6个字母组成的字符串
print(r)
print(s)
print(t)
['pyt', 'hon', 'jav', 'php'] #结果
['python', 'java', 'php']
['pyt', 'hon', 'jav', 'php']
Python默认是以贪婪模式来匹配的,即尽可能多的匹配字符。{3,6}
匹配到3个字符时已经满足条件,但仍然不够,直到匹配到6个字符为止。
import re
a = 'pytho0python1pythonn2'
r = re.findall('python*', a) #匹配0次或多次的字符n
s = re.findall('python+', a) #匹配1次或多次的字符n
t = re.findall('python?', a) #匹配0次或1次的字符n
print(r)
print(s)
print(t)
['pytho', 'python', 'pythonn'] #结果
['python', 'pythonn']
['pytho', 'python', 'python']
边界匹配:^
、$
。
^
匹配字符串的开头;$
匹配字符串的末尾。
import re
a = 'pytho0, python1, 2python'
r = re.findall('^python', a) #匹配a是否以'python'字符串开头
s = re.findall('python$', a) #匹配a是否以'python'字符串结尾
t = re.findall('^python$', a) #匹配a是否以'python'字符串开头并以'python'字符串结尾
print(r)
print(s)
print(t)
[] #结果
['python']
[]
组:()
,匹配括号内的表达式,()
内的表达式就表示一个组,是一个整体。
import re
a = 'PythonPythonPythonPythonPython'
r = re.findall('(Python){3}', a)
print(r)
['Python'] #结果
在python中,如果想要使用正则表达式,需要先导入re模块:
import re
字符串的startswith()
方法表示以指定字符串开头,匹配到则返回True,否则返回False;
字符串的endswith()
方法表示以指定字符串结尾,匹配到则返回True,否则返回False。
str1 = 'Linux Python'
a = str1.startswith('linux')
b = str1.startswith('Linux')
print(a)
print(b)
False #结果
True
>>> re.
re.A re.LOCALE re.Scanner( re.compile( re.fullmatch( re.sre_parse
re.ASCII re.M re.T re.copyreg re.functools re.sub(
re.DEBUG re.MULTILINE re.TEMPLATE re.enum re.match( re.subn(
re.DOTALL re.Match( re.U re.error( re.purge( re.template(
re.I re.Pattern( re.UNICODE re.escape( re.search(
re.IGNORECASE re.RegexFlag( re.VERBOSE re.findall( re.split(
re.L re.S re.X re.finditer( re.sre_compile
re模块在python3中有这些方法,下面介绍一些常用的方法,通过这些方法进行匹配。
pattern:匹配的正则表达式
string:要匹配的字符串
flags:标记为,用于控制正则表达式的匹配方式。如:是否区分大小写,多行匹配等等
repl:替换的字符串,也可作为一个函数
count:模式匹配后替换的最大次数,默认0表示替换所有匹配
maxsplit:模式匹配后分割的最大次数,默认0表示不分割
re.findall
会找到匹配字符串,返回所有非重复匹配项的列表。
用法:re.findall(pattern, string, flags=0)
import re
a = 'C|C++|Java|C#|Python|Javascript'
r = re.findall('Python', a) #匹配字符串中的'Python'
if len(r) > 0:
print('字符串中包含Python')
print(r)
字符串中包含Python #结果
['Python']
import re
a = 'C6Java2C#7Python9c#Javascript'
r = re.findall('c#', a, re.I) #不区分大小写匹配字符串c#
print(r)
['C#', 'c#'] #结果
flags是re.I
时不区分大小写匹配,flags是re.S
时则.
可以匹配包括换行符的任意字符。此外,flags是re.M
时可以多行匹配。
替换字符串中每一个匹配的子串后返回替换后的整个字符串。
用法:re.sub(pattern, repl, string, count=0, flags=0)
import re
a = 'PythonC#JavaC#PHPC#'
r = re.sub('C#', 'GO', a, 1)
s = a.replace('C#', 'GO')
print(r)
print(s)
PythonGOJavaC#PHPC# #结果
PythonGOJavaGOPHPGO
可以看出,count表示模式匹配后替换的最大次数,默认0表示替换所有匹配,count=1
时只替换一次。replace()
函数与re.sub有些类似。
import re
a = 'PythonC#JavaC#PHPC#'
def convert(value):
matched = value.group() #调用group()方法取到匹配值
return '!!' + matched + '!!'
r = re.sub('C#', convert, a) #把函数作为参数传入
print(r)
Python!!C#!!Java!!C#!!PHP!!C#!! #结果
repl
写成函数作为参数传入,此时pattern
会作为函数的参数传入,函数的结果会替换pattern
,返回替换后的string
。上例中,C#
作为参数传入convert()
,返回的是一个对象,通过调用group()
方法拿到匹配的值。
当pattern
不是常量的时候,把repl
作为函数传入,这样我们就可以根据不同的匹配结果,动态地做不同的处理操作。
import re
a = 'A8C3721D86' #要求把字符串中不小于6的数字替换为9,小于6的数字替换为0
def convert(value):
matched = value.group()
if int(matched) >= 6:
return '9'
else:
return '0'
r = re.sub('\\d', convert, a)
print(r)
A9C0900D99 #结果
上面就是简单的动态处理,将函数作为一个参数传入另一个函数。另外,把函数作为参数传入的函数是高阶函数
。
re.match
从字符串的起始位置匹配,返回第一个匹配对象(不是匹配的值)。
用法:re.match(pattern, string, flags=0)
re.search
在一个字符串中查找匹配,返回第一个匹配对象(不是匹配的值)。
用法:re.search(pattern, string, flags=0)
import re
a = 'A8C3721D86'
r = re.match('\\d', a)
s = re.search('\\d', a)
matched = s.group()
print(r)
print(s)
print(matched)
None #结果
<re.Match object; span=(1, 2), match='8'>
8
因为re.match
从起始位置匹配,而起始位置不是数字,所以返回None;而re.search
是在字符串中匹配,返回第一个匹配对象(不是匹配的值)。
而且re.match
和re.search
都是在匹配到后立刻返回匹配对象后然后停止匹配,这与re.findall
是不一样的,re.findall
会返回所有匹配到的值。
前面讲到,()
可以表示一个组,group()
方法则可以取到不同分组的值。默认是group(0)
,即要匹配的字符串。分组可以有多个,group(1)
表示第一个分组的值,group(2)
表示第二个分组的值,依次类推。
此外,对于多个分组,还可以使用groups()
,groups()
只会返回所有分组的值组成的元组。
import re
a = 'life is short, i use python' #取life后、python前的字符串(包含空字符串)
r = re.search('life(.*)python', a)
print(r.group(0))
print(r.group(1))
life is short, i use python #结果
is short, i use
可以看出,re.match
和re.search
使用不是很方便,相比之下还是re.findall
更好用。
JSON是JavaScript Object Notation的简写,意思是JavaScript对象标记,它是一种轻量级的数据交换格式,是REST服务的标准格式。
给个定义的话,JSON就是一种数据格式。字符串是JSON的表现形式,符合JSON格式的字符串称为JSON字符串。
易于阅读
易于解析(跨语言交换数据)
网络传输效率高
JSON字符串:'{"name":"张小喜", "age":18}'
规定类型:{}
内必须使用双引号将字符串括起来,数字除外;{}
外根据python再使用单引号将{}
括起来。
在Python中,有专门处理json格式的模块:json
和picle
模块。不同的是json模块序列化出来的是通用格式,其它编程语言都认识,就是普通的字符串;而picle模块序列化出来的只有python可以认识,其他编程语言不认识的,表现为乱码。
json和pickle模块都提供了四个方法:dumps()
、dump()
、loads()
、load()
。
dumps()和dump()是序列化方法。dumps()只完成了序列化为str;dump()必须传文件描述符,将序列化的str保存到文件中。
loads()和load()是反序列化方法。loads()只完成了反序列化;load()只接收文件描述符,完成了读取文件和反序列化。
import json
json_str = '{"name":"张小喜", "age":18}' #json字符串
student = json.loads(json_str)
print(type(student))
print(student)
print(student['name'])
print(student['age'])
<class 'dict'> #结果 #python解析为字典
{'name': '张小喜', 'age': 18}
张小喜
18
对于json字符串对象,python会解析为字典。
import json
json_str = '[{"name":"张小喜", "age":18}, {"name":"张小喜", "age":18}]' #json字符串对象组成的数组
student = json.loads(json_str)
print(type(student))
print(student)
<class 'list'> #结果 #python解析为列表
[{'name': '张小喜', 'age': 18}, {'name': '张小喜', 'age': 18}]
对于json字符串对象组成的数组,python会解析为列表。
把字节序列恢复为数据结合或对象的过程称为反序列化。下面解析对应关系:
json | python |
---|---|
object | dict |
array | list |
string | str |
number | int |
number | float |
true | True |
false | False |
null | None |
有反序列化,肯定也有序列化。把数据结构或对象转换为字节序列的过程称为序列化。
import json
student = [
{'name': '张小喜', 'age': 18, 'flag': False},
{'name': '张小喜', 'age': 18}
]
json_str = json.dumps(student)
print(type(json_str))
print(json_str)
<class 'str'> #结果
[{"name": "\u5f20\u5c0f\u559c", "age": 18, "flag": false}, {"name": "\u5f20\u5c0f\u559c", "age": 18}]