第10章 正则表达式(重点)与JSON
初识正则表达式
(1)正则表达式 是一个特殊的 字符序列,检测 一个字符串 是否与我们所设定的这样的字符序列,相匹配。 (即字符串是否与正则表达式相匹配)
快速检索文本、实现一些替换文本的操作。
正则表达式是用来操作字符串的。
正则表达式的应用:
1.检查一串数字是否是电话号码
2.检测一个字符串是否符合email
3.把一个文本里指定的单词替换为另外一个单词
(2)简单的字符判断时,优先选择python的内置函数:
a = 'C|C++|Java|C#|Python|Javascript'
print(a.index('Python')>-1)
print('Python' in a)
输出:
True
True
(3)如何运用正则表达式:
Python中提供了一个 re模块:其中很多的方法可以用来操作正则表达式。
import re
a = 'C|C++|Java|C#|Python|Javascript'
r = re.findall('Python',a) #匹配常量字符串 #调用了re模块的findall方法
# r=re.findall('正则表达式',a)
print(r)
if len(r) > 0:
print('字符串中包含Puython')
输出:
['Python']
字符串中包含Puython
元字符与普通字符
(1)上小节中举的例子匹配的常量字符串,没有真正发挥正则表达式的意义。
import re
a = 'C0C++7Java8C#9Python6Javascript' #找数字
r = re.findall('\d',a) # \d可以表示数字0-9
print(r)
输出:
['0', '7', '8', '9', '6']
(2)上一节例子中组成正则表达式的 python ————叫做普通字符
像这里例子中的 ‘ \d ’ 组成正则表达式 ———— ‘ \d ’ 叫做元字符
正则表达式就是由一系列的普通字符与元字符组合而成的。学习正则表达式主要是学习元字符,不要死记硬背,根据自己的需求,去元字符表中查询就可以了。
字符集
字符集的特性
# 字符集
import re
s = 'abc, acc, adc, aec, afc, ahc'
(1)
r = re.findall('a[cf]c',s) # []
print(r)
输出:['acc', 'afc']
(2)
r = re.findall('a[^cf]c',s) # ^
print(r)
输出:['abc', 'adc', 'aec', 'ahc']
(3)
r = re.findall('a[c-f]c',s) # -
print(r)
输出:['acc', 'adc', 'aec', 'afc']
概括字符集
(1)例如:“\d”也是概括字符集的一种 :代表数字0-9。
(2)
\w —————— 既能匹配数字又能匹配字母,它匹配的范围:[A-Za-z0-9_]
(即大写字母A到Z,小写字母a到z,数字0到9,还可以匹配下划线)(只能匹配单词字符)(只能匹配一个字符)
\W ———— 大写匹配非单词字符
import re
a = 'python1111java&__678php'
r = re.findall('\w',a) #不能匹配到&这种非单词字符
print(r)
输出:
['p', 'y', 't', 'h', 'o', 'n', '1', '1', '1', '1', 'j', 'a', 'v', 'a', '_', '_', '6', '7', '8', 'p', 'h', 'p']
import re
a = 'python1111java&__678php'
r = re.findall('\W',a) #大写匹配非单词字符
print(r)
输出:['&']
常见的非单词字符:\n , \r , \t,‘ ’
(3)
\s ———— 匹配空白字符
\S ———— 匹配非空白字符
import re
a = 'python11 \t11java&\n678\rphp'
r = re.findall('\s',a)
print(r)
输出:
[' ', '\t', '\n', '\r']
数量词
(1)[a-z]
import re
a = 'python 1111java678php'
r = re.findall('[a-z]',a)
print(r)
输出:
['p', 'y', 't', 'h', 'o', 'n', 'v', 'j', 'a', 'v', 'a', 'p', 'h', 'p']
(2)数量词的用法: {数字1,数字2}
import re
a = 'python 1111java678php'
r = re.findall('[a-z]{3,6}',a)
print(r)
输出:['python', 'java', 'php']
贪婪与非贪婪
(1)
默认情况下是贪婪的匹配方式:如果把数量词限定在一个区间内,会尽可能多的取最大的一个区间内的值。
例如:上小节的例子中[a-z]{3,6}
匹配区间是3到6,匹配到‘pyt’时,并不会认为成立,它会匹配更多(贪婪的),直到匹配完‘python’。
(2)非贪婪(如何表示:在区间后加上问号)
import re
a = 'python 1111java678php'
r = re.findall('[a-z]{3,6}?',a)
print(r)
输出:
['pyt', 'hon', 'jav', 'php']
注:在这个例子中 界限 取3是非贪婪,取6是贪婪
匹配0次1次或者无限多次
(1)*
* : 表示匹配 *前面的字符 0次或无限多次
import re
a = 'pytho0python1pythonn2'
r = re.findall('python*',a)
print(r)
输出:['pytho', 'python', 'pythonn']
注:第一个'pytho'缺少一个n,符合匹配0次
python,匹配一次
pythonn,匹配2次
(2)+
+ : 匹配1次或者无限多次
把 * 换成 + 会输出:['python', 'pythonn']
(3)?
?: 匹配0次或1次
输出:['pytho', 'python', 'python']
注:多出来的n会被去掉。可以用? 做去重操作。
如果问号前有数量词的话就从数量词中选交小的数作为匹配次数
(4)
import re
a = 'pytho0python1pythonn2'
r = re.findall('python{1,2}',a) #匹配一次或两次
print(r)
输出:['python', 'pythonn']
r = re.findall('python{1,2}?',a) # ?:非贪婪:匹配一次
输出:['python', 'python']
r = re.findall('python?',a) # ?:匹配0次或一次
输出:['pytho', 'python', 'python']
边界匹配符(^ 、$)
import re
a = '1000019090890'
# 验证位数是否为4-8位
r = re.findall('\d{4,8}',a)
print(r)
输出:['10000190', '90890']
r = re.findall('^\d{4,8}$',a)
输出:[]
^ : 表示从字符串的开始进行匹配
$ : 表示从字符串的末尾开始匹配
两个一前一后:匹配完整的字符
import re
a = '100000001'
r = re.findall('000',a)
print(r)
输出:['000', '000']
r = re.findall('^000',a) —————————— 表示的匹配条件: 字符串开始三个数字是000
输出:[]
r = re.findall('000$',a) —————————— 表示的匹配条件:字符串最后三个数字是000
输出:[]
组
import re
a = 'PythonPythonPythonPythonPython' # 判断该字符串里是否包含三个Python
r = re.findall('(Python){3}(JS)',a) # 用‘PythonPythonPython’作为表达式当然可以,但不简洁
print(r)
# 括起来的一系列字符就叫组 加上数量词,就表示把一组的字符重复若干次
# 可以有多个组,例如后面可以加一个(JS),这也是一个组
中括号里面是或关系,小括号里面是且关系。[abc] :表示匹配a或b或c;(Python) :表示每个字符都出现。
匹配模式参数
作用:忽略大小写的差异
import re
a = 'PythonC#JavaPHP'
r = re.findall('c#',a,re.I)
print(r)
输出:['C#']
多个模式之间用竖线隔开
. 表示匹配除换行符\n之外其他所有字符
import re
a = 'PythonC#\nJavaPHP'
r = re.findall('c#.{1}',a,re.I | re.S) # re.S:让 " . " 匹配所有字符包括\n
print(r)
输出:['C#\n']
r = re.findall('c#.{1}',a,re.I) # 如果不加re.S则 “.” 不会匹配 \n
输出:[]
re.sub正则替换
(1)用re模块中的sub函数来实现替换:re.sub
import re
a = 'PythonC#JavaC#PHP'
r = re.sub('C#','Go',a,0) # 参数为0时把所有C#替换成Go
print(r)
输出:PythonGoJavaGoPHP
r = re.sub('C#','Go',a,1) # 参数为1时只有第一个匹配到的C#替换成了Go
print(r)
输出:PythonGoJavaC#PHP
(2)一些简单的替换可以用 内置函数 replace:
import re
a = 'PythonC#JavaC#PHP'
a.replace('C#','Go')
print(a)
输出:PythonC#JavaC#PHP
这里并没有被替换掉,是因为字符串不可变,要改变的话就要新生成一个变量来接收。代码如下:
import re
a = 'PythonC#JavaC#PHP'
r = a.replace('C#','Go')
print(r)
输出:PythonGoJavaGoPHP
(3)
import re
a = 'PythonC#JavaC#PHP'
def convert(value):
pass
r = re.sub('C#',convert,a)
print(r)
输出:PythonJavaPHP
如果我们把 一个函数 作为 sub函数 的第二个参数:当正则表达式匹配到结果时,会把匹配到的结果传到该函数。
这里convert 函数中的value即正则表达式匹配到的结果‘C#’, 这里convert函数的返回结果会替换‘C#’
返回的并不只是一个简单的字符串'C#',而是一个对象
import re
a = 'PythonC#JavaC#PHP'
def convert(value):
print(value)
# return '!!'+value+'!!'
r = re.sub('C#',convert,a)
print(r)
输出:
<re.Match object; span=(6, 8), match='C#'> # 这里的span是匹配到的位置,是第7、8位
<re.Match object; span=(12, 14), match='C#'> # 第二次匹配到的位置时13、14位
PythonJavaPHP
不能对返回的对象直接操作,所以用group方法获取匹配到的字符串
import re
a = 'PythonC#JavaC#PHP'
def convert(value):
matched = value.group()
return '!!'+ matched +'!!'
r = re.sub('C#',convert,a)
print(r)
输出:Python!!C#!!Java!!C#!!PHP
把函数作为参数传递
import re
a = 'A8C3434D378'
#实现把大于等于6的替换成9,否则替换为0
def convert(value):
matched = value.group()
if matched >=6:
return 9
else:
return 0
r = re.sub('\d',convert,a)
print(r)
这里运行会报错:报错 一是因为现在数字是以字符串的形式出现的,要先类型转换一下。二是 也不能直接把整型数字返回,因为是用正则表达式,它只能操作字符串。
更改代码如下:
def convert(value):
matched = value.group()
if int(matched) >=6:
return '9'
else:
return '0'
输出:A9C0000D099
从这个例子可以理解把函数作为参数接收的重要意义:实现把一些复杂的逻辑赋予参数。自己在平常编写代码时可以多试试如何运用这样的形式。多思考。
search 与 match函数
(1)
match函数特征:从字符串 首字符 开始进行匹配,如果没有匹配成功,则返回None。第一个匹配成功则马上返回结果。
search函数特征:搜索字符串,一般找到结果之后,就马上返回结果。
(2)例子
import re
s='A8C3434D378'
r= re.match('\d',s) #从字符串开始就要匹配,这里开头不是数字,所以返回None
print(r)
r1 = re.search('\d',s)
print(r1)
输出:
None
<re.Match object; span=(1, 2), match='8'>
import re
s='88C3434D378'
r= re.match('\d',s)
print(r)
r1 = re.search('\d',s)
print(r1.group())
输出:
<re.Match object; span=(0, 1), match='8'>
8
(3)span() 方法 是返回正则匹配结果在原字符串的位置
import re
s='88C3434D378'
r= re.match('\d',s)
print(r.span())
输出:(0, 1)
(4)search 与 match 函数与findall函数区别:
group 与 match 函数:如果匹配成功,将立刻返回当前匹配到的结果,不会继续往前搜索。
findall 函数:会把所有匹配结果都打印出来
group分组
(1)问题引入:提取life和python之间的字符
代码1:
import re
s='life is short,i use python'
r= re.match('life.*python',s)
print(r.group())
输出:life is short,i use python
(2)探索:
group 实际上获取的是一个分组匹配的值
代码二:
import re
s='life is short,i use python'
# 提取life和python之间的字符
r= re.match('(life.*python)',s)
print(r.group(0))
输出:life is short,i use python
结果与代码一的结果一样:因为正则表达式默认是一个分组
group函数可以传入参数,代表组号,这里只有一个组,参数传0或者不写都可以。
group(0)比较特殊,记录的永远是正则表达式的完整匹配的结果。
代码三:
若想访问完整匹配的内部的结果:应该改为:
r= re.match('life(.*)python',s)
print(r.group(1))
输出结果: is short,i use
上面的例子用search函数也是一样的。
(3)用findall 函数
import re
s='life is short,i use python'
# 提取life和python之间的字符
r= re.findall('life(.*)python',s)
print(r)
输出:[' is short,i use ']
推荐findall函数,更简洁快速。
(4)关于group
import re
s='life is short,i use python, i love python'
# 提取life和python之间的字符
r= re.search('life(.*)python(.*)python',s) # 出现了两个分组
print(r.group(0,1,2))
输出:
('life is short,i use python, i love python', ' is short,i use ', ', i love ')
import re
s='life is short,i use python, i love python'
# 提取life和python之间的字符
r= re.search('life(.*)python(.*)python',s)
print(r.groups())
groups不会返回完整的匹配结果
输出:(' is short,i use ', ', i love ')
一些关于学习正则的建议
(1)善于运用正则表达式 解决字符串相关的问题
(2)对于电话号码的判断、qq号的判断、邮箱的判断等非常常见的校验规则,可以用别人已经写好的,不必要自己去编写,从而提高工作效率。
(3)从学习角度:还是可以分析一下别人的正则表达式是怎么写的,平时有意识的使用正则表达式。
理解JSON
(1)什么是JSON:
是一种轻量级的数据 交换格式。JSON是一种数据格式。字符串是JSON的表现形式。
符合JSON格式的字符串叫做JSON字符串。
(2)JSON优势:易阅读,易解析,网络传输效率高,适合跨语言交换数据。
总结:
1.JSON是为了做数据交换而定制的一个规则和规范。JSON的载体:JSON字符串。
2.JSON是跨语言的。
反序列
(1)JSON数据类型 如何转换到 Python数据类型?
import json
json_str = '{"name":"qiyue","age":18}'
#在JSON字符串中,除了数字类型其他都要加引号,且规定只能是双引号(JSON规定),那么外层就只能是单引号了(Python规定)。
#这里的{"name":"qiyue","age":18}就是符合JSON规范的JSON字符串了,这里的JSON也可以看做是object(对象)
student = json.loads(json_str)
print(type(student))
print(student)
输出:
<class 'dict'>
{'name': 'qiyue', 'age': 18}
# 说明通过load函数已经把把JSON字符串转化为了字典,下面打印出的是一个字典
print(student['name'])
print(student['age'])
输出:
qiyue
18
(2)对于同样的JSON字符串,不同的语言可能会把它变成不同的数据类型。在Python中转换成字典,在其他语言是不一定的。
(3)如果JSON是一个数组的话,JSON字符串怎么表示。
import json
json_str = '[{"name":"qiyue","age":18},{"name":"qiyue","age":18}]'
student = json.loads(json_str)
print(type(student))
print(student)
输出:
<class 'list'>
[{'name': 'qiyue', 'age': 18}, {'name': 'qiyue', 'age': 18}]
import json
json_str = '[{"name":"qiyue","age":18,"flag":false},{"name":"qiyue","age":18}]'
#false不是字符串,不用加引号
student = json.loads(json_str)
print(type(student))
print(student)
输出:
<class 'list'>
[{'name': 'qiyue', 'age': 18, 'flag': False}, {'name': 'qiyue', 'age': 18}]
#把JSON中的小写false变成了大写,因为在Python中是大写的。
这里示例是想说明 :JSON是有自己的数据类型的,我们用 loads 函数是为了 把JSON的数据类型转换为Python的数据类型。
(4)反序列化的定义(了解):由字符串到语言下的某一种数据结构的这一过程 叫做反序列化。
序列化
(1)JSON与Python之间的类型对照表。
(2) Python数据类型向JSON字符串转换的一个过程——————叫做序列化
import json
student = [
{'name':'qiyue','age':18,'flag':False},
{'name':'qiyue','age':18}
]
json_str = json.dumps(student) #字典也是对象
print(type(json_str))
print(json_str)
输出:
<class 'str'>
[{"name": "qiyue", "age": 18, "flag": false}, {"name": "qiyue", "age": 18}]
扩展:不只是python与JSON之间的转换才叫 序列化 或 反序列化。
(3)序列化的意义:通过调用服务得到JSON字符串,然后转换为Python的数据结构,从而获取到JSON字符串里面的相关信息。
小谈JSON、JSON对象与JSON字符串(了解)
(1)
JSON (JavaScript Object Notation) :仅仅是一种数据格式,可以跨平台数据传输,速度快。
JavaScript :是一个标准的实现方案之一,服务器的一种语言。是一个类的实例。不能传输。
Json字符串:符合JSON格式的字符串叫做JSON字符串。(所谓字符串:单引号或者双引号引起来 )
Json对象: 最显著的特征:对象的值可以用 “对象.属性” 进行访问
(2)