正則表達式
- 動機
- 文本處理已經成為計算機的常見工作之一
- 對文本內容的搜索,定位,提取是邏輯比較復雜的工作
- 為了快速解決上述問題,產生了正則表達式技術
- 定義
- 即文本的高級匹配模式,提供搜索,替代等功能。其本質是一系列由特殊符號組成的字串,這個字串即正則表達式。
- 匹配原理
- 由普通字符和特殊符號組成字符串,通過描述字符的重復和位置等行為,達到匹配某一類字符串的目的
- 目標
- 熟練掌握正則表達式符號
- 實現基本的文本搜索,定位,提取,理解正則用法
- 能夠適用re模塊操作正則表達式
- 特點
- 方便文本處理
- 支持語言眾多
- 使用靈活多樣
re模塊
re.findall(pattern, string)
- 功能:使用正則表達式匹配目標字符串內容
- 參數:
- pattern 正則表達式
- string 目標字符串
- 返回值:列表,列表中為匹配到的內容
元字符的使用
1. 普通字符
- 元字符:a b c...
- 匹配規則:每個字符匹配對應的字符
import re
re.findall("hello", "hello world")
['hello']
re.findall("您好", "您好北京")
['您好']
2. 或
- 元字符:|
- 匹配規則:匹配 | 兩邊任意一個正則表達式
print(re.findall("ab|cd", "abcdefghijk"))
print(re.findall("abc|cde", "abcdefghijk")) # 不匹配已經匹配過的
['ab', 'cd']
['abc']
3. 匹配單個字符
- 元字符: .
- 匹配規則:匹配除換行外的任意字符
f.o --> foo fao f@o f o
re.findall("f.o", "foo is not fao f o f@o")
['foo', 'fao', 'f o', 'f@o']
4. 匹配開始位置
- 元字符 : ^
- 匹配規則:匹配目標字符串的開頭位置
re.findall("^Tom", "Tom is a boy")
['Tom ']
5. 匹配結束位置
- 元字符 : $
- 匹配規則:匹配字符串的結束位置
re.findall("boy$", "Tom is a boy")
['boy']
6. 匹配重復
- 元字符 : *
- 匹配規則:匹配前面的字符出現0次或多次
fo* --> fooooooooo f fo
re.findall("fo*", "fadsfafooooafo") # 匹配o出現0次或多次
['f', 'f', 'foooo', 'fo']
7. 匹配重復
- 元字符: +
- 匹配規則:匹配前面的字符出現1次或多次
fo+ --> fo fooooo
re.findall("fo+", "fadsfafooooafo")
['foooo', 'fo']
8. 匹配重復
- 元字符:?
- 匹配規則:匹配前面的字符出現0次或1次
fo? --> f fo
re.findall("fo?", "fadsfafooooafo")
['f', 'f', 'fo', 'fo']
9. 匹配重復{n}
- 元字符 : {n}
- 匹配規則: 匹配指定的重復次數
fo{3} --> fooo
re.findall("fo{2}", "fadsfafooooafo")
['foo']
10. 匹配重復{m,n}
- 元字符: {m,n}
- 匹配規則:匹配前面的正則表達式 m--n次
fo{2,4} --> foo fooo foooo
re.findall("fo{2,4}", "fadsfafooooafoo")
['foooo', 'foo']
匹配所用字符表達為:.+或.*
11. 匹配字符集合
- 元字符: [字符集]
- 匹配規則: 匹配任意一個字符集中的字符
[abc123] a b c 1 2 3
[a-z]
[A-Z]
[0-9]
[_123a-z]
re.findall("[A-Z][a-z]*", "Boy")
['Boy']
12. 匹配字符集(非)
- 元字符 : [^...]
- 匹配規則 :字符集取非,除列出的字符之外任意一個字符
[^abc] --> 除a b c之外任意字符
re.findall("[^ ]+", "a little boy")
['a', 'little', 'boy']
13. 匹配任意數字字符
- 元字符 : \d \D
- 匹配規則:
\d 匹配任意數字字符 [0-9]
\D 匹配任意非數字字符 [^0-9]
re.findall("1\d{10}", "17857024541")
['17857024541']
14. 匹配任意(非)普通字符
- 元字符 : \w \W
- 匹配規則:
\w 普通字符 [_0-9a-zA-Z] 也能匹配普通漢字
\W 非普通字符
re.findall("\w+", "hello#nihao%adsd@afsd!df&")
['hello', 'nihao', 'adsd', 'afsd', 'df']
re.findall("\W+","hello#nihao%asdf@adsgdfg!df&")
['#', '%', '@', '!', '&']
15. 匹配任意(非)空字符
- 元字符:
\s 匹配任意空字符 [空格 \r\t\n\v\f]
\S 匹配任意非空字符
re.findall("\w+\s+\w+", "hello world")
['hello world']
re.findall("\S+", "hello this is tom")
['hello', 'this', 'is', 'tom']
16. 匹配字符串位置
- 元字符 : \A \Z
- 匹配規則:
\A 匹配字符串開頭位置 ^
\Z 匹配字符串結尾位置 $
絕對匹配:正則表達式要完全匹配目標字符串內容
- 在正則表達式開始和結束位置加上^ $ (或者\A \Z)。這樣正則表達式必須匹配整個目標字符串才會有結果
re.findall("\A\d+\Z","123445")
['123445']
17. 匹配(非)單詞邊界
- 元字符: \b \B
- 匹配規則:
\b 匹配單詞邊界位置
普通字符和非普通字符交界認為是單詞邊界
\B 匹配非單詞邊界位置
re.findall(r"num\b", "num#asdf#")
['num']
re.findall(r"num\b", "numasdf#")
[]
元字符總結
匹配單個字符 : a . \d \D \w \W \s \S
[...] [^...]
匹配重復 : * + ? {n} {m,n}
匹配位置 : ^ $ \A \Z \b \B
其他 : | () \
正則表達式轉義
-
正則中的特殊符號:
. * + ? ^ $ [] {} () | \ -
正則表達式如果匹配特殊字符需要加 \ 表達轉義
正則 目標字符串 e.g. \$\d+ ----> $10 pattern string python "\\$\\d+" "$10" raw r"\$\d+" "$10" raw字串 : 原始字符串對內容不解釋轉義,就表達內容原本意義
貪婪與非貪婪
-
貪婪模式 : 正則表達式的重復匹配總是盡可能多的向后匹配更多內容
* + ? {m,n}
-
非貪婪(懶惰模式) : 盡可能少的匹配內容
貪婪 ---> 非貪婪 *? +? ?? {m,n}?
re.findall(r"ab+?", "abbbbbbbb")
['ab']
re.findall(r"ab??", "abbbbbbbb")
['a']
正則表達式的子組
- 可以使用()為正則表達式建立子組,子組可以看做是正則表達式內部操作的一個整體
- 子組是在正則表達式整體匹配到內容的前提下才會發揮作用,它不影響正則表達式整體去匹配目標內容這一原則
子組所用
-
作為內部整體可以改變某些元字符的行為
re.search(r"(ab)+\d+","ababab1234").group()
'ababab1234're.search(r"\w+@\w+\.(com|cn)","abc@123.com").group() 'abc@123.com'
-
子組在某些操作中可以單獨提取出匹配內容
re.search(r"(https|http|ftp)😕/\S+","https://www.baidu.com").group(1)
Out[121]: 'https'
子組使用注意事項
- 一個正則表達式中可以有多個子組
- 子組一般由外到內,由左到右稱之為第一,第二 第三。。。。子組
- 子組不能重疊,嵌套也不宜很多
捕獲組 和 非捕獲組
- 格式:
(?P<name>pattern)
e.g.
re.search(r"(?Pab)cdef",'abcdefghti').group('dog')
Out[130]: 'ab' - 作用 : 可以通過組名更方便獲取某組內容
正則表達式設計原則
-
正確性 ,能正確匹配到目標內容
-
排他性 ,除了要匹配的內容,盡可能不會匹配與到其他內容
-
全面性 ,需要對目標的各種情況進行考慮,做到不遺漏
regex = compile(pattern,flags = 0)
功能 : 生成正則表達式對象
參數 : pattern 正則表達式
flags 功能標志位,豐富正則表達式的匹配功能
返回值 : 返回正則表達式對象re.findall(pattern,string,flags)
功能 :從目標字符串查找正則匹配內容
參數 : pattern 正則表達式
string 目標字符串
flags 標志位
返回值 : 返回匹配到的內容
如果正則有子組則只返回子組對應內容regex.findall(string,pos,endpos)
功能 :從目標字符串查找正則匹配內容
參數 : string 目標字符串
pos 匹配目標的起始位置
endpos 匹配目標的終止位置
返回值 : 返回匹配到的內容
如果正則有子組則只返回子組對應內容re.split(pattern,string,flags = 0)
功能:根據正則匹配內容切割字符串
參數: pattern string flags
返回值: 返回列表,列表中為切割的內容re.sub(pattern,replaceStr,string,max,flags)
功能: 替換正則匹配到的目標子串部分
參數: pattern
replaceStr : 要替換的內容
string
max 最多替換幾處 默認全部替換
flags
返回值 : 返回替換后的字符串re.subn(pattern,replaceStr,string,max,flags)
功能: 替換正則匹配到的目標子串部分
參數: pattern
replaceStr : 要替換的內容
string
max 最多替換幾處 默認全部替換
flags
返回值 : 返回一個元組,為實際替換了幾處和替換后的字符串re.finditer(pattern,string,flags)
功能: 使用正則表達式匹配目標字符串
參數: pattern string flags
返回值: 返回一個迭代對象,迭代到的內容是一個match對象fullmatch(pattern,string,flags)
功能: 完全匹配目標字符串
參數: pattern,string,flags
返回值:返回匹配到的match對象
如果沒匹配成功返回Nonematch(pattern,string,flags)
功能: 從開頭位置匹配目標字符串
參數: pattern,string,flags
返回值:返回匹配到的match對象
如果沒匹配成功返回Nonesearch(pattern,string,flags)
功能: 正則表達式匹配目標字符串,只匹配第一處
參數: pattern,string,flags
返回值:返回匹配到的match對象
如果沒匹配成功返回Nonecompile對象屬性:
flags : 標志位
pattern : 正則表達式
groups: 有多少子組
groupindex : 捕獲組形成組名和序列號的字典
組名為鍵,第幾組為值
pattern = r"(ab)cd(ef)"
s = "abcdefghigkabcdef"
#re模塊直接調用
l = re.findall(pattern,s)
print(l)
#compile對象調用
regex = re.compile(pattern)
l = regex.findall(s)
print(l)
print("==================================")
l = re.split(r"\s+","Hello world nihao China")
print("split():",l)
s = re.sub(r"\s+","#",'Hello world nihao China',2)
print("sub():",s)
s = re.subn(r"\s+","#",'Hello world nihao China')
print("subn():",s)
[('ab', 'ef'), ('ab', 'ef')]
[('ab', 'ef'), ('ab', 'ef')]
==================================
split(): ['Hello', 'world', 'nihao', 'China']
sub(): Hello#world#nihao China
subn(): ('Hello#world#nihao#China', 3)
import re
it = re.finditer(r'\d+',"2008-2018 10年,\
中國發生了翻天覆地的變化")
for i in it:
print(i.group())
#fullmatch
try:
obj = re.fullmatch(r"\w+",'abcdef123')
print(obj.group())
except AttributeError as e:
print(e)
#match
obj = re.match(r'foo',"foo,food on the table")
print(obj.group())
#search
obj = re.search(r'foo',"Foo,food on the table")
print(obj.group())
2008
2018
10
abcdef123
foo
foo
match對象屬性
- 屬性變量
- pos 匹配目標字符串的開始位置
- endpos 匹配目標字符串的結束位置
- re 正則表達式
- string 目標字符串
- lastgroup 最后一組的組名
- lastindex 最后一組是第幾組
- 屬性方法
- span() 匹配內容的開始位置
- start() 匹配內容的結束位置
- end() 匹配內容的起止位置
group()
- 功能 : 獲取match對象對應的內容
- 參數 : 默認為0 表示獲取整個正則匹配的內容
如果為序列號或者子組名則為獲取某個子組匹配的對應內容 - 返回值:返回得到的子串
groupdict() 獲取捕獲組名作為鍵,對應內容作為值的字典
groups() 獲取每個子組匹配內容
import re
pattern = r"(?P<dog>ab)cd(?P<pig>ef)"
regex = re.compile(pattern)
#獲取match對象
match_obj = regex.search("abcdefghij",pos = 0,endpos = 6)
print(match_obj.pos) #匹配目標字符串的開始位置
print(match_obj.endpos) #匹配目標字符串的結束位置
print(match_obj.re) #正則表達式
print(match_obj.string) #目標字符串
print(match_obj.lastgroup) #最后一組的組名
print(match_obj.lastindex) #最后一組是第幾組
print("=============================")
print(match_obj.start()) #匹配內容的開始位置
print(match_obj.end()) #匹配內容的結束位置
print(match_obj.span()) #匹配內容的起止位置
print(match_obj.group(0)) #獲取整個match對象內容
print(match_obj.group(2)) #獲取第二個子組匹配內容
print(match_obj.group('dog')) #獲取dog子組匹配內容
print(match_obj.groupdict()) #獲取捕獲組字典
print(match_obj.groups()) #獲取每個子組匹配內容
0
6
re.compile('(?P<dog>ab)cd(?P<pig>ef)')
abcdefghij
pig
2
=============================
0
6
(0, 6)
abcdef
ef
ab
{'dog': 'ab', 'pig': 'ef'}
('ab', 'ef')
flags 參數的使用
re.compile re.findall re.search re.match
re.finditer re.fullmatch re.sub re.subn re.split
- 作用 : 輔助正則表達式,豐富匹配結果
I == IGNORECASE 匹配時忽略字母的大小寫
S == DOTALL 作用於元字符 . 使其可以匹配換行
M == MULTILINE 作用於^ $ 使其可以匹配每一行開頭結尾位置
X == VERBOSE 可以給正則添加注釋
使用多個標志位使用按位或連接
e.g.
flags = re.X | re.I
import re
s = '''hello world
hello kitty
你好,北京'''
pattern = r'''H\w+ #匹配第一個單詞
\s+ #匹配多個空格
[a-z]+ #匹配其他
'''
regex = re.compile(pattern,flags = re.X | re.I)
try:
s = regex.search(s).group()
except:
print("沒有匹配到內容")
else:
print(s)
hello world