1.概述
正則表達式是一個特殊的字符序列,一個字符串是否與我們所設定的字符序列相匹配
主要用于快速檢索文本、實現一些替換文本的操作
例如:
(1)檢查一串數字是否是電話號碼
(2)檢查一個字符串是否符合email
(3)把一個文本里指定的單詞替換為另一個單詞
2.初識
不使用正則表達式查找字符串中某個單詞
a = 'C|C++|Java|Python|C#|Javascript'
print(a.index('Python') > -1)
print('Python' in a)
==>
True
True
使用正則表達式:要用到Python的模塊re
import re
a = 'C|C++|Java|Python|C#|Javascript'
r = re.findall('Python',a)
print(r)
if len(r) > 0:
print('字符串中包含Python')
else:
print('No')
==>
['Python']
字符串中包含Python
3.數字正則表達式
b = 'C0C++7Java8Python9C#6Javascript'
需求:找出字符串中所有的數字
(1)方法1:for in 循環找出所有的數字
(2)方法2:
import re
b = 'C0C++7Java8Python9C#6Javascript'
re.findall('0' , b)
re.findall('1' , b)
re.findall('2' , b)
re.findall('3' , b)
.....
re.findall('9' , b)
(3)方法3:
import re
b = 'C0C++7Java8Python9C#6Javascript'
r = re.findall('\d' , b) #\d表示所有的數字
print(r)
==>
['0', '7', '8', '9', '6']
4.正則表達式類型
(1)普通字符 'Python'
(2)元字符
例如:'\d' 匹配一個數字字符。等價于[0-9]
'\D' 匹配一個非數字字符。等價于[^0-9]
(3)普通字符和元字符混合
參考鏈接:https://baike.baidu.com/item/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F
https://www.runoob.com/regexp/regexp-metachar.html
5.字符集
import re
s = 'abc, acc, adc, aec, afc, ahc'
#找出所有中間字母為c或者f的單詞
r = re.findall('a[cf]c', s)
print(r)
#找出所有中間字符非c或f或d的單詞
r1 = re.findall('a[^cdf]c',s)
print(r1)
#找出所有中間字符為c或d或e或f的單詞
r2 = re.findall('a[c-f]c',s)
print(r2)
==>
['acc', 'afc']
['abc', 'aec', 'ahc']
['acc', 'adc', 'aec', 'afc']
6.概括字符集
'\d' 匹配一個數字字符。等價于[0-9]
'\D' 匹配一個非數字字符。等價于[^0-9]
[\w] 匹配包括下劃線的任何單詞字符。類似但不等價于“[A-Za-z0-9_]”,這里的"單詞"字符使用Unicode字符集,例如 & 是匹配不到的
[\W] 匹配任何非單詞字符。等價于[^A-Za-z0-9_] 包含空格、回車、制表符等
[\s] 匹配任何不可見字符,包括空格、制表符、換頁符等等。等價于[ \f\n\r\t\v]
[\S] 匹配任何可見字符。等價于[^ \f\n\r\t\v]
.點 匹配除“\n”和"\r"之外的任何單個字符。要匹配包括“\n”和"\r"在內的任何字符,請使用像“[\s\S]”的模式
a = 'C#\rpython_11&11 java\n678\tphp'
r1 = re.findall('[0-9]',a)
print(r1)
r2 = re.findall('[^0-9]',a)
print(r2)
r3 = re.findall('\w',a)
print(r3)
r4 = re.findall('\W',a)
print(r4)
r5 = re.findall('\s',a)
print(r5)
r6 = re.findall('\S',a)
print(r6)
r7 = re.findall('.',a)
print(r7)
==>
['1', '1', '1', '1', '6', '7', '8']
['C', '#', '\r', 'p', 'y', 't', 'h', 'o', 'n', '_', '&', ' ', 'j', 'a', 'v', 'a', '\n', '\t', 'p', 'h', 'p']
['C', 'p', 'y', 't', 'h', 'o', 'n', '_', '1', '1', '1', '1', 'j', 'a', 'v', 'a', '6', '7', '8', 'p', 'h', 'p']
['#', '\r', '&', ' ', '\n', '\t']
['\r', ' ', '\n', '\t']
['C', '#', 'p', 'y', 't', 'h', 'o', 'n', '_', '1', '1', '&', '1', '1', 'j', 'a', 'v', 'a', '6', '7', '8', 'p', 'h', 'p']
['C', '#', '\r', 'p', 'y', 't', 'h', 'o', 'n', '_', '1', '1', '&', '1', '1', ' ', 'j', 'a', 'v', 'a', '6', '7', '8', '\t', 'p', 'h', 'p']
7.數量詞
(1)?
當該字符緊跟在任何一個其他限制符(*,+,?,{n},{n,},{n,m})后面時,匹配模式是非貪婪的。非貪婪模式盡可能少地匹配所搜索的字符串,而默認的貪婪模式則盡可能多地匹配所搜索的字符串。例如,對于字符串“oooo”,“o+”將盡可能多地匹配“o”,得到結果[“oooo”],而“o+?”將盡可能少地匹配“o”,得到結果 ['o', 'o', 'o', 'o']
貪婪:盡可能匹配最大設置數量來做匹配,盡可能匹配更多,滿足3時,不會立刻滿足并返回結果,還會繼續往下匹配,因此會匹配出python
例如:[a-z]{3,6} 會盡可能按照[a-z]{6}做匹配
非貪婪:[a-z]{3,6}? 一旦滿足3,就返回結果了
import re
a = 'ptho0python1pythonn2'
r = re.findall('[a-z]{3,6}',a)
print(r)
r1 = re.findall('[a-z]{3,6}?',a)
print(r1)
==>
['ptho', 'python', 'python']
['pth', 'pyt', 'hon', 'pyt', 'hon']
(2)*
匹配前面的子表達式任意次。例如,zo能匹配“z”,也能匹配“zo”以及“zoo”。等價于{0,}
import re
a = 'pytho0python1pythonn2'
r3 = re.findall('python*',a)
print(r3)
==>
['pytho', 'python', 'pythonn']
(3)+
匹配前面的子表達式一次或多次(大于等于1次)。例如,“zo+”能匹配“zo”以及“zoo”,但不能匹配“z”。+等價于{1,}
import re
a = 'pytho0python1pythonn2'
r3 = re.findall('python+',a)
print(r3)
==>
['python', 'pythonn']
(4)?
匹配前面的子表達式零次或一次。例如,“do(es)?”可以匹配“do”或“does”。?等價于{0,1}
import re
a = 'pytho0python1pythonn2'
r3 = re.findall('python?',a)
print(r3)
==>
['pytho', 'python', 'python']
8.邊界匹配
qq = '100001'
需求:校驗QQ號是否合規,要求QQ號必須在4-8位之間
錯誤方法:
r = re.findall('\d{4,8}',qq)
#qq號小于4位時,能篩選出錯誤的qq號
#當qq = '1000000001' 為9位時,上方語句也能匹配出來,這樣就錯了
正確方法:
#從行首開始匹配,滿足4-8字符,同時后邊緊跟著行尾
r = re.findall('^\d{4,8}$',qq)
^:匹配輸入字行首。如果設置了RegExp對象的Multiline屬性,^也匹配“\n”或“\r”之后的位置
$:匹配輸入行尾。如果設置了RegExp對象的Multiline屬性,$也匹配“\n”或“\r”之前的位置
qq = '100001'
r1 = re.findall('^000',qq)
print(r1)
r2 = re.findall('000$',qq)
print(r2)
==>
[]
[]
9.以單詞為最小單位匹配,用()括起來即可
a = 'PythonPythonPythoPythonPythonPython'
#匹配是否有連續3個Python
r = re.findall('(Python){3}',a)
print(r)
r1 = re.findall('(Python){4}',a)
print(r1)
==>
['Python']
[]
10.匹配模式
language = 'PythonC#\nJavaPHP'
r = re.findall('c#',language)
print(r)
==>
[]
#匹配不到
修飾符 | 描述 |
---|---|
re.I | 使匹配對大小寫不敏感 |
re.S | 使 . 匹配包括換行在內的所有字符 |
re.L | 做本地化識別(locale-aware)匹配 |
re.M | 多行匹配,影響 ^ 和 $ |
re.U | 根據Unicode字符集解析字符。這個標志影響 \w, \W, \b, \B. |
re.X | 該標志通過給予你更靈活的格式以便你將正則表達式寫得更易于理解。 |
使用re.I使匹配對大小寫不敏感
language = 'PythonC#\nJavaPHP'
r = re.findall('c#',language,re.I)
print(r)
==>
['C#']
需求:匹配到c#和其后邊的一個換行符
language = 'PythonC#\nJavaPHP'
r = re.findall('c#.{1}',language,re.I)
==>
[]
#匹配不到,因為.點無法匹配“\n”和“\r”這種字符
使用re.S使 . 匹配包括換行在內的所有字符
language = 'PythonC#\nJavaPHP'
r = re.findall('c#.{1}',language,re.I | re.S)
print(r)
==>
['C#\n']
11.re.sub 正則替換
import re
language = 'PythonC#JavaC#PHPC#'
r = re.sub('C#','GO',language)
#上述語句等同于r = re.sub('C#','GO',language,0),意思是字符串的C#全部替換
print(r)
==>
PythonGOJavaGOPHPGO
可以選擇不全部替換'C#'
language = 'PythonC#JavaC#PHPC#'
r = re.sub('C#','GO',language,1)
print(r)
==>
PythonGOJavaC#PHPC#
language = 'PythonC#JavaC#PHPC#'
r = re.sub('C#','GO',language,2)
print(r)
==>
PythonGOJavaGOPHPC#
全部替換也可以用另一個函數:replace
language = language.replace('C#','GO')
print(language)
==>
PythonGOJavaGOPHPGO
sub函數的第二個參數不僅可以是一個常量,也可以是一個函數
例如:
import re
def convert(value):
pass
language = 'PythonC#JavaC#PHPC#'
r = re.sub('C#',convert,language)
print(r)
==>
PythonJavaPHP
源字符串如果有'C#',則'C#'會作為函數convert的入參,convert的輸出則將替換'C#',上方因為convert輸出為空,因此所有'C#'消失了
打印一下函數convert的入參value
def convert(value):
print(value)
==>
<re.Match object; span=(6, 8), match='C#'>
<re.Match object; span=(12, 14), match='C#'>
<re.Match object; span=(17, 19), match='C#'>
原來value不單純只是一個字符串,而是一個對象,那么怎么直接拿到對象的內容?使用group()函數
def convert(value):
matched = value.group()
return '!!'+ matched + '!!'
language = 'PythonC#JavaC#PHPC#'
r = re.sub('C#',convert,language)
print(r)
==>
Python!!C#!!Java!!C#!!PHP!!C#!!
12.練習
字符串s = 'A83C27D1D8E67'
按如下規則進行字符串轉換:
(1)找到所有數字,數字為1位則刪掉
(2)數字為2位,則判斷數字是否大于等于50,若是,則替換為99;若不是,則替換為00
答案:
s = 'A83C27D1D8E67'
def convert(value):
matched = value.group()
if len(matched) < 2:
return ''
elif int(matched) >= 50:
return '99'
else:
return '00'
r = re.sub('\d{1,2}',convert,s)
print(r)
==>
A99C00DDE99
13.match和search
s = 'A83CF8943GH44'
#match從字符串的第一個字符開始匹配,匹配不到\d就返回None
r1 = re.match('\d',s)
print(r1)
#search從整個字符串進行搜索,當搜索到第一個符合條件的字符時就返回該字符,并停止搜索
r2 = re.search('\d',s)
print(r2)
==>
None
<re.Match object; span=(1, 2), match='8'>
14.group()
import re
s = 'life is short,i use python'
s1 = 'life is short,i use python,i love python'
r = re.findall('life(.*)python',s)
print(r)
r = re.search('life(.*)python(.*)python',s1)
print(r.group(0))
print(r.group(1))
print(r.group(2))
print(r.groups())
==>
[' is short,i use '] # 用圓括號括起來,可以不輸出邊界,只輸出想要的部分
life is short,i use python,i love python #group(0)默認輸出全部
is short,i use #group(1)輸出第一個圓括號中的內容
,i love #group(2)輸出第二個圓括號中的內容
(' is short,i use ', ',i love ') #groups()把兩個括號中的內容合成一個元組輸出
15.JSON是一種輕量級的數據交換格式
(1)和XML相比,JSON很輕量
字符串是JSON的表現形式
符合JSON格式的字符串,就是JSON字符串
JSON是跨語言的,在每一種語言基本都能找到相對應的數據格式
import json
json_str = '{"name":"huluwa", "age":18}'
json_str1 = '[{"name":"huluwa", "age":18, "flag":false},{"name":"test", "age":28}]'
# 注意點:
# 1.key一定要用雙引號引起來,單引號不行(與語言無關)
# 2.字符串一定要用雙引號引起來,單引號不行(與語言無關),數字不需要引起來
# 3.python內部有雙引號,最外部一定要用單引號(與python有關)
student = json.loads(json_str)
print(type(student))
print(student)
student1 = json.loads(json_str1)
print(type(student1))
print(student1)
==>
<class 'dict'>
{'name': 'huluwa', 'age': 18}
<class 'list'>
[{'name': 'huluwa', 'age': 18, 'flag': False}, {'name': 'test', 'age': 28}]
(2)反序列化
# 從字符串轉化成語言下的某種數據類型的過程,叫做反序列化,反之則叫做序列化;
# json.loads()就是一個反序列化的過程,下面來看一下序列化:
student2 = [
{'name':'huluwa','age':18,'flag':False},
{'name':'test','age':28}
]
print(type(student2))
json_str2 = json.dumps(student2)
print(type(json_str2))
print(json_str2)
==>
<class 'list'> #student2本來是list類型
<class 'str'> #經過json.dumps()之后變成了字符串類型
[{"name": "huluwa", "age": 18, "flag": false}, {"name": "test", "age": 28}]
(3)JSON和python數據類型對應列表
JSON | python |
---|---|
object | dict |
array | list |
string | str |
number | int |
number | float |
true | True |
false | False |
null | None |