学习笔记,参考:
- 正则表达式
- 视频:https://www.bilibili.com/video/av16926522/?p=36
- 和爬虫很相关
- 字符串前加 r,表示的意思是禁止字符串转义(参考 python 字符串前面r的作用)
print('yo\nu')
print(r'yo\nu')
output
yo
u
yo\nu
图片来源 https://www.cnblogs.com/huxi/archive/2010/07/04/1771073.html
1 简单的匹配
没接触过 regular expression 的时候,用 in
来做字符串的匹配!
# matching string
s1 = "bryant"
s2 = "lola"
string = "bryant runs to enchanter"
print(s1 in string)
print(s2 in string)
output
True
False
正则表达式无非就是在做这么一回事. 在文字中找到特定的内容
import re
# regular expression
s1 = "bryant"
s2 = "lola"
string = "bryant runs to enchanter"
print(re.search(s1, string)) # <_sre.SRE_Match object; span=(12, 15), match='cat'>
print(re.search(s2, string)) # None
output
<_sre.SRE_Match object; span=(0, 6), match='bryant'>
None
返回一个 match 的 object,如果没有匹配到, 它会返回 None
再看一个例子
import re
text = "Kobe Bryant is my favorite basketbal star!"
result = re.search("my", text)
print(True if result else False)
output
True
2 灵活的匹配
匹配潜在的多个可能性文字,比如单词的不同时态,以 run
和 ran
为例
# multiple patterns ("run" or "ran")
s3 = r"r[au]n"
print(re.search(s3, "bryant runs to enchanter"))
print(re.search(s3, "bryant ran to enchanter"))
output
<_sre.SRE_Match object; span=(7, 10), match='run'>
<_sre.SRE_Match object; span=(7, 10), match='ran'>
[]
中可以推广延伸成所有数字,或所有大小写字母
print(re.search(r"r[A-Z]n", "bryant rUns to enchanter"))#匹配所有大写字母
print(re.search(r"r[a-z]n", "bryant runs to enchanter"))#匹配所有小写字母
print(re.search(r"r[0-9]n", "bryant r2ns to enchanter"))#匹配所有数字
print(re.search(r"r[0-9a-zA-Z]n", "bryant rUns to enchanter"))#匹配所有大写、小写、数字(单个字符)
print(re.search(r"r[0-9][a-z][A-Z]n", "bryant r0aUns to enchanter")) #第一字符匹配所有数字,第二个所有小写字母,第三个所有大写字母
output
<_sre.SRE_Match object; span=(7, 10), match='rUn'>
<_sre.SRE_Match object; span=(7, 10), match='run'>
<_sre.SRE_Match object; span=(7, 10), match='r2n'>
<_sre.SRE_Match object; span=(7, 10), match='rUn'>
<_sre.SRE_Match object; span=(7, 12), match='r0aUn'>
3 按类型匹配
上图中 \w “” 为 _
1)按数字匹配 \d
import re
# \d : decimal digit
print(re.search(r"r\dn", "run r4n"))
# \D : any non-decimal digit
print(re.search(r"r\Dn", "run r4n"))
output
<_sre.SRE_Match object; span=(4, 7), match='r4n'>
<_sre.SRE_Match object; span=(0, 3), match='run'>
2)按 white space 匹配 \s
参考 1.2.3 转义字符
import re
# \s : any white space [\t\n\r\f\v]
print(re.search(r"r\sn", "r\nn r4n"))
# \S : opposite to \s, any non-white space
print(re.search(r"r\Sn", "r\nn r4n"))
output
<_sre.SRE_Match object; span=(0, 3), match='r\nn'>
<_sre.SRE_Match object; span=(4, 7), match='r4n'>
3)按任何大小写字母, 数字和 _ 匹配 \w
import re
# \w : [a-zA-Z0-9_]
print(re.search(r"r\wn", "r\nn r4n"))
print(re.search(r"r\wn", "r\nn run"))
print(re.search(r"r\wn", "r\nn rUn"))
print(re.search(r"r\wn", "r\nn r_n"))
# \W : opposite to \w
print(re.search(r"r\Wn", "r\nn r4n"))
output
<_sre.SRE_Match object; span=(4, 7), match='r4n'>
<_sre.SRE_Match object; span=(4, 7), match='run'>
<_sre.SRE_Match object; span=(4, 7), match='rUn'>
<_sre.SRE_Match object; span=(4, 7), match='r_n'>
<_sre.SRE_Match object; span=(0, 3), match='r\nn'>
4)按首尾的空白字符匹配 \b
指单词和空格间的位置。例如, ‘er\b’ 可以匹配"never" 中的 ‘er’,但不能匹配 “verb” 中的 ‘er’。
import re
# \b : empty string (only at the start or end of the word)
print(re.search(r"er\b", "never"))
print(re.search(r"er\b", "verb"))
print(re.search(r"er\b", "ver b"))
print(re.search(r"\ber\b", "v er b"))
# \B : empty string (but not at the start or end of a word)
print(re.search(r"er\B", "verb"))
output
<_sre.SRE_Match object; span=(3, 5), match='er'>
None
<_sre.SRE_Match object; span=(1, 3), match='er'>
<_sre.SRE_Match object; span=(2, 4), match='er'>
<_sre.SRE_Match object; span=(1, 3), match='er'>
5)匹配任何字符.,除 \n .
import re
# . : match anything (except \n)
print(re.search(r"r.n", "r[n to me"))
print(re.search(r"r.n", "r_n to me"))
print(re.search(r"r.n", "r\n to me"))
print(re.search(r"r.n", r"r\n to me"))
output
<_sre.SRE_Match object; span=(0, 3), match='r[n'>
<_sre.SRE_Match object; span=(0, 3), match='r_n'>
None
<_sre.SRE_Match object; span=(0, 3), match='r\\n'>
字符串前加 r
,禁止强制转化就可以检测 \
了
6)转义字符 \
import re
print(re.search(r"l\.ove", "I l.ove enchanter"))
print(re.search(r"l\*ove", "I l*ove enchanter"))
print(re.search(r"l\\ove", "I l\ove to enchanter"))
output
<_sre.SRE_Match object; span=(2, 7), match='l.ove'>
<_sre.SRE_Match object; span=(2, 7), match='l*ove'>
<_sre.SRE_Match object; span=(2, 7), match='l\\ove'>
注意,虽然 \ 匹配的结果为 \,但是从 span 的范围可以看出,还是 \
7)匹配开头 ^
import re
# ^ : match line beginning
print(re.search(r"^bryant", "bryant runs to enchanter"))
print(re.search(r"^enchanter", "bryant runs to enchanter"))
output
<_sre.SRE_Match object; span=(0, 6), match='bryant'>
None
8)匹配结尾 $
import re
# ^ : match line beginning
print(re.search(r"bryant$", "bryant runs to enchanter"))
print(re.search(r"enchanter$", "bryant runs to enchanter"))
output
None
<_sre.SRE_Match object; span=(15, 24), match='enchanter'>
9) 匹配一个字符0次或1次 ?
import re
# ? : may or may not occur
print(re.search(r"do(es)?", "do")) # 0 次
print(re.search(r"do(es)?", "does")) # 1 次
print(re.search(r"I do(es)?", "yes, I do"))
output
<_sre.SRE_Match object; span=(0, 2), match='do'>
<_sre.SRE_Match object; span=(0, 4), match='does'>
<_sre.SRE_Match object; span=(5, 9), match='I do'>
10)匹配多行中某一行的开头 flags=re.M
import re
string = '''
bryant runs to enchanter,
enchanter runs to bryant.
'''
print(re.search(r"^bryant", string))
print(re.search(r"^bryant", string, flags=re.M))
print(re.search(r"^enchangter", string))
print(re.search(r"^enchanter", string, flags=re.M))
output
None
<_sre.SRE_Match object; span=(1, 7), match='bryant'>
None
<_sre.SRE_Match object; span=(27, 36), match='enchanter'>
4 重复匹配
1)*:重复零次或多次
import re
# * : occur 0 or more times
print(re.search(r"ab*", "a"))
print(re.search(r"ab*", "abbbbb"))
output
<_sre.SRE_Match object; span=(0, 1), match='a'>
<_sre.SRE_Match object; span=(0, 6), match='abbbbb'>
2)+:重复一次或多次
import re
# + : occur 1 or more times
print(re.search(r"ab+", "a"))
print(re.search(r"ab+", "ab"))
print(re.search(r"ab+", "abbbbb"))
output
None
<_sre.SRE_Match object; span=(0, 2), match='ab'>
<_sre.SRE_Match object; span=(0, 6), match='abbbbb'>
3){n, m}:重复 n 至 m 次
import re
# {n, m} : occur n to m times
print(re.search(r"ab{0,10}", "a"))
print(re.search(r"ab{2,10}", "a"))
print(re.search(r"ab{2,10}", "abbbbb"))
output
<_sre.SRE_Match object; span=(0, 1), match='a'>
None
<_sre.SRE_Match object; span=(0, 6), match='abbbbb'>
4){n} : 重复 n 次
# {n} : occur n times
print(re.search(r"ab{1}", "a"))
print(re.search(r"ab{1}", "ab"))
print(re.search(r"ab{2}", "ab"))
output
None
<_sre.SRE_Match object; span=(0, 2), match='ab'>
None
5 分组
import re
match = re.search(r"(\d+), Date: (.+)", "ID: 123456, Date: April/19/2019")
print(match.group())
print(match.group(1))
print(match.group(2))
\d
匹配数字,+
重复一次或多次,.
匹配除 \n
外所有字符
output
123456, Date: April/19/2019
123456
April/19/2019
根据数字索引有时候会混淆,可以给组取个名字 ?P<名字>
import re
match = re.search(r"(?P<id>\d+), Date: (?P<date>.+)", "ID: 123456, Date: April/19/2019")
print(match.group('id'))
print(match.group('date'))
output
123456
April/19/2019
6 findall / replace / split / compile
1)findall
前面只找到了最开始匹配上的一项, 使用 findall
功能可找到全部的匹配项, 然后返回一个列表. |
表示 or
import re
# findall
print(re.findall(r"r[ua]n", "run ran ren"))
# | : or
print(re.findall(r"(run|ran)", "run ran ren"))
output
['run', 'ran']
['run', 'ran']
统计检索出来的数量时配合 len
就行
eg:元音统计
import re
string = "super"
result = re.findall(r"[aeiou]", string, re.IGNORECASE)
print(result)
print(len(result))
output
['u', 'e']
2
2)replace
替换掉匹配的项
import re
print(re.sub(r"r[au]ns", "flies", "bryant runs to enchanter"))
output
bryant flies to enchanter
3)split
Python 字符串的分割功能,参考 Python 字符串
"a is b".split(" ")
output
['a', 'is', 'b']
re 版
import re
print(re.split(r"[,;.]", "a,b,c.d;e"))
output
['a', 'b', 'c', 'd', 'e']
4)compile
使用 compile
过后的正则, 来对这个正则重复使用.
import re
compiled_re = re.compile(r"r[ua]n")
print(compiled_re.search("bryant ran to enchanter"))
output
<_sre.SRE_Match object; span=(7, 10), match='ran'>