通用字符匹配
语法 | 通配符匹配作用解析 |
. | 匹配除换行符之外的任意一个字符 |
* | 匹配前一个字符出现零次或任意多次 |
+ | 匹配前一个字符出现1次或任意多次 |
? | 匹配前一个字符出现1次或0次 |
^ | 匹配以指定字符开头的数据 |
$ | 匹配以指定字符结尾的数据 |
{m} | 匹配前一个字符出现过m次的记录 |
{n,m} | 匹配前一个字符,最少出现n次,最多出现m次 |
匹配任意一个字符(.) 默认匹配除\n之外的任意一个字符,若指定flag=DOTALL则匹配包括换行在内的字符.
"hel.o","hello lyshark,hello world").group() | re.search(|
'hello' | |
"hel.o","hello lyshark hello world") | re.findall(|
['hello', 'hello'] |
匹配前一个字符出现0至任意多次(*) 匹配星号前面的字符出现0次,或任意多次.
>>> re.findall("ab*","abccba23acbcabb") | |
['ab', 'a', 'a', 'abb'] |
匹配前一个字符出现1次或任意多次(+) 匹配加号前面的字符出现过1次,或任意多次,至少出现一次.
>>> re.findall("ab+","abccba23acbcabb") | |
['ab', 'abb'] |
匹配前一个字符出现1次或0次(?) 匹配前一个字符出现过1次或0次,允许出现0次.
>>> re.findall("ab?","ab,abc,abb,abcd,a,acd,abc") | |
['ab', 'ab', 'ab', 'ab', 'a', 'a', 'ab'] | |
>>> re.findall("ab?","ab,a,abc,abcde") | |
['ab', 'a', 'ab', 'ab'] |
匹配开头与结尾(^): ^匹配指定字符开头的数据,匹配指定字符结尾的数字.
r"^h","hello world").group() | re.search(|
'h' | |
r"world$","hello\nworld").group() | re.search(|
'world' | |
r"^a","\nabc\ndef",flags=re.MULTILINE).group() | re.search(|
'a' | |
"foo$","bfoo\nsdfsf",flags=re.MULTILINE).group() | re.search(|
'foo' |
匹配前一个字符出现次数(x{m}) 匹配前一个字符x,出现过m次的行.
>>> re.search("hello{2}","hello,helloo,hellooo,helloooo").group() | |
'helloo' | |
>>> re.search("hello{3}","hello,helloo,hellooo,helloooo").group() | |
'hellooo' |
匹配前一个字符出现次数(x{n,m}) 匹配前一个字符x,最少出现过n次,最多出现过m次.
"hello{1,2}","hello,helloo,hellooo,helloooo").group() | re.search(|
'hello' | |
"hello{1,2}","hello,helloo,hellooo,helloooo") | re.findall(|
['hello', 'helloo', 'helloo', 'helloo'] |
脱意字符的匹配(\) 转义字符,通常情况下使后一个字符改变原来的意思,也叫做脱意字符.
"..\\t","hello\t lyshark\n").group() | re.search(|
'lo\t' | |
"\\t","hello\t lyshark\n").group() | re.search(|
'\t' | |
"\t","hello\t lyshark\n").group() | re.search(|
'\t' | |
r"\\","hello\\lyshark").group() | re.search(|
'\\' |
匹配查找范围([]) 匹配查找指定的数据范围,通常使用[0-9] [a-z] [A-Z]
这几个匹配格式.
"[0-9]","hello 1,2,3,4,5").group() # 匹配第一次出现数字的行 | re.search(|
'1' | |
"[0-9]","hello a12 b23 34a 45t").group() | re.search(|
'1' | |
"[0-9]","hello 1,2,3,4,5") # 匹配所有出现数字的行 | re.findall(|
['1', '2', '3', '4', '5'] | |
"[0-9]","hello b23 34a 45t wan") | re.findall(|
['2', '3', '3', '4', '4', '5'] | |
"[^0-9]","hello 1,2,3,4,5").group() # 匹配开头不是0-9的单个字符 | re.search(|
'h' | |
"[^0-9]*","hello 1,2,3,4,5").group() # 匹配开头不是0-9的单行行 | re.search(|
'hello' | |
r"[aeiou]","Hello LyShark").group() | re.search(|
'e' |
匹配查找空白字符(s) 匹配空白字符
>>> re.search("\s+","ab\tc1\n3").group() | |
'\t' | |
>>> re.search("\s+","ab c1\n3").group() | |
' ' |
选择性匹配(|) 匹配选择竖线左边,或者右边的任意一种情况.
"abc|ABC","ABCBabcCD").group() | re.search(|
'ABC' | |
"abc|ABC","ABCBabcCD") | re.findall(|
['ABC', 'abc'] |
实现分组匹配((?P...)) 匹配条件并自动分组,其中?P<..>是固定写法,后面紧跟正则规则.
>>> number = "371481199306143242" | |
>>> re.search("(?P<province>[0-9]{4})(?P<city>[0-9]{2})(?P<birthday>[0-9]{4})",number).groupdict() | |
{'province': '3714', 'city': '81', 'birthday': '1993'} | |
>>> re.search("(?P<name>[a-zA-Z]+)(?P<age>[0-9]+)","lyshark22").groupdict("temp") | |
{'name': 'lyshark', 'age': '22'} |
针对IP地址与MAC地址的提取:
"^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$","192.168.1.1") | re.search(|
<re.Match object; span=(0, 11), match='192.168.1.1'> # 匹配IP地址 | |
r"^\s*\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\s*$","192.168.1.100") | re.match(|
<re.Match object; span=(0, 13), match='192.168.1.100'> # 匹配IP地址 | |
"is this 236.168.192.1 ip 12321" | string_ip =|
r"\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b", string_ip) | result = re.findall(|
result | |
['236.168.192.1'] | |
compile(r'((1\d\d|2[0-4]\d|25[0-5]|[1-9]\d|\d)\.){3}(1\d\d|2[0-4]\d|25[0-5]|[1-9]\d|\d)') | string=re.|
print(string.search('245.255.256.25asdsa10.11.244.10').group()) | |
10.11.244.10 | |
"1050:0:0:0:5:600:300c:326b" # 匹配IPV6地址(大小写不敏感) | string_IPv6=|
r"^(?:[A-F0-9]{1,4}:){7}[A-F0-9]{1,4}$", string_IPv6, re.I) | re.match(|
<re.Match object; span=(0, 26), match='1050:0:0:0:5:600:300c:326b'> | |
r"(?<![:.\w])(?:[A-F0-9]{1,4}:){7}[A-F0-9]{1,4}(?![:.\w])", string_IPv6, re.I) | re.findall(|
['1050:0:0:0:5:600:300c:326b'] | |
r"^\s*([0-9a-fA-F]{2,2}:){5,5}[0-9a-fA-F]{2,2}\s*$","AB:1F:44:5B:3B:4A") | re.match(|
<re.Match object; span=(0, 17), match='AB:1F:44:5B:3B:4A'> # 匹配一个MAC地址 |
针对网址与端口的匹配:
r"^(http|https?:\/\/)([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$","https://www.baidu.com") | re.search(|
<re.Match object; span=(0, 21), match='https://www.baidu.com'> # 匹配网址 | |
r"([0-9]|[1-9]\d{1,3}|[1-5]\d{4}|6[0-4]\d{4}|65[0-4]\d{2}|655[0-2]\d|6553[0-5])","hello 443") | re.findall(|
['4', '4', '3'] # 匹配端口号 | |
r'^(http|https?:\/\/)([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?(:([0-9]|[1-9]\d{1,3}|[1-5]\d{4}|6[0-4]\d{4}|65[0-4]\d{2}|655[0-2]\d|6553[0-5]))?$',"http://www.baidu.com:80") | re.search(|
<re.Match object; span=(0, 23), match='http://www.baidu.com:80'> | |
r'^(\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])(:([0-9]|[1-9]\d{1,3}|[1-5]\d{4}|6[0-4]\d{4}|65[0-4]\d{2}|655[0-2]\d|6553[0-5]))?$',"192.168.1.100:443") | re.search(|
<re.Match object; span=(0, 17), match='192.168.1.100:443'> |
针对时间格式的匹配:
r"(\d{4}-\d{1,2}-\d{1,2})","2019-01-12") | re.search(|
<re.Match object; span=(0, 10), match='2019-01-12'> | |
r"(\d{4}-\d{1,2}-\d{1,2})","2019-01-12,2010-12-11") | re.findall(|
['2019-01-12', '2010-12-11'] | |
r"\d{4}[-/]\d{2}[-/]\d{2}","2019-01-12,2010/12/11") | re.findall(|
['2019-01-12', '2010/12/11'] | |
r"(\d{1,2}/(Jan|Feb|Mar|Apr|Jun|Jul|Aug|Sep|Oct|Nov|Dec)/\d{4})","2019-01-12,21/Nov/2019").group() | re.search(|
'21/Nov/2019' | |
r"(\d{1,2}:\d{1,2})","2010-12-11 12:11") | re.findall(|
['12:11'] | |
r"(\d{1,2}:\d{1,2}:\d{1,2})","2010-12-11 12:11:22,09:25:30") | re.findall(|
['12:11:22', '09:25:30'] | |
r"(\d{4}-\d{1,2}-\d{1,2}\s\d{1,2}:\d{1,2})","2010-12-11 12:11") | re.search(|
<re.Match object; span=(0, 16), match='2010-12-11 12:11'> | |
r"(\d{4}-\d{1,2}-\d{1,2}\s\d{1,2}:\d{1,2})","2010-12-11 12:11") | re.findall(|
['2010-12-11 12:11'] |
匹配邮箱/手机号/身份证:
"^1[3|4|5|8]\d{9}$","18264856987") | re.search(|
<re.Match object; span=(0, 11), match='18264856987'> # 匹配手机号 | |
"[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+","182648@qq.com") | re.search(|
<re.Match object; span=(0, 13), match='182648@qq.com'> # 匹配一个邮箱 | |
r'(^[1-8][0-7]{2}\d{3}([12]\d{3})(0[1-9]|1[012])(0[1-9]|[12]\d|3[01])\d{3}([0-9X])$)',"33070219630306041X") | re.findall(|
[('33070219630306041X', '1963', '03', '06', 'X')] # 匹配身份证号 |
针对密码验证的匹配: 此处的匹配正则常用于用户名密码的过滤.
"[\u4e00-\u9fa5]","你好") | re.findall(|
['你', '好'] # 匹配中文字符 | |
"^[\u4e00-\u9fa5_a-zA-Z0-9]{4,10}$","1233") | re.findall(|
['1233'] # 单纯限制字符的输入长度 | |
r"^[a-zA-Z][a-zA-Z0-9_]{4,15}$","password") | re.findall(|
['password'] # 允许输入最小5-15个字符的密码,允许使用下划线. | |
r"^[a-zA-Z]\w{5,17}$","passw3") | re.findall(|
['passw3'] # 以字母开头,长度在6~18之间,只能包含字母、数字和下划线 | |
"^(?!_)(?!.*?_$)[a-zA-Z0-9_\u4e00-\u9fa5]+$","1233") | re.findall(|
['1233'] # 限制不能以下划线开头和结尾 |
常用匹配函数
函数与方法名 | 通配符匹配作用解析 |
regex.match | 从字符串开头位置匹配查找,如果0个或多个字符被匹配则返回相应的匹配对象,如果不匹配则返回None. |
regex.search | 扫描整个字符串,查找正则匹配到的字串中第一次出现的位置,并返回相应的匹配对象,如果匹配失败则返回None. |
regex.findall | 搜索字符串中与正则表达式匹配的所有子串,也就是查找字符串中所有的匹配结果,并且以列表的形式返回数据. |
regex.sub | 字符串的替换,简单来说就是替换字符串中与正则表达式匹配的指定数量的子串,最后返回替换修改后的字符串. |
regex.split | 以正则表达式匹配的字符串作为分隔符,对一个字符串进行分割,以列表形式返回分割后的各个字符串. |
match.expand | 通过得到的匹配对象来构造并返回一个新的字符串,未被匹配到的分组将被替换为一个空字符串. |
match.group | 返回一个或多个指定捕获组所匹配到的内容,如果只有1个参数则返回单独的字符串,多参数返回元组. |
match.groups | 返回一个包含所有分组所匹配内容的元组,如果某个分组没有匹配到内容,则取defalult所指定的值. |
match.groupdict | 返回一个包含所有命名分组名称及其所匹配内容的字典对象,如果某个分组没有匹配到内容则取默认值. |
regex.match() 从起始位置开始匹配,匹配成功返回一个对象,未匹配成功返回None.
match(pattern,string,flags=0) | |
# pattern: 正则模型 | |
# string : 要匹配的字符串 | |
# falgs : 匹配模式 | |
#------------------------------------------------ | |
# 未分组情况下. | |
"hello alex bcd abcd lge acd 19" | origin =|
"h\w+",origin) | ret = re.match(|
print(ret.group()) #获取匹配到的所有结果 | |
print(ret.groups()) #获取模型中匹配到的分组结果 | |
print(ret.groupdict()) #获取模型中匹配到的分组结果 | |
# 有分组情况下. 提取匹配成功的指定内容(先匹配成功全部正则,再匹配成功的局部内容提取出来) | |
"h(\w+).*(?P<name>\d)$",origin) | ret = re.match(|
print(r.group()) #获取匹配到的所有结果 | |
print(r.groups()) #获取模型中匹配到的分组结果 | |
print(r.groupdict()) #获取模型中匹配到的分组中所有执行了key的组 |
regex.search() 搜索整个字符串去匹配第一个符合条件的数据,未匹配成功返回None.
"hello alex bcd abcd lge acd 19" | origin =|
>>> | |
"^h\w+",origin).group() #匹配开头是h的后面是任意字符的 | re.search(|
'hello' | |
"a\w+",origin).group() #匹配a开头后面是任意字符的 | re.search(|
'alex' | |
"(?P<name>a\w+)",origin).groupdict() | re.search(|
{'name': 'alex'} #分组匹配并过滤出alex | |
"(?P<姓名>[a-zA-Z]+)(?P<年龄>[0-9]+)","lyshark22").groupdict() | re.search(|
{'姓名': 'lyshark', '年龄': '22'} #匹配字符串,并分组打印出结果 |
regex.findall() 获取非重复的匹配列表,且每一个匹配均是字符串,空的匹配也会包含在结果中.
"hello alex bcd abcd lge acd 19" | origin =|
"al\w+",origin) | re.findall(|
['alex'] #匹配到单个结果,则以单列表返回 | |
"a\w+",origin) | re.findall(|
['alex', 'abcd', 'acd'] #匹配到多个结果,则以列表形式返回 |
regex.sub() 先匹配查找结果,然后进行字串的替换,也就是替换匹配成功的指定位置字符串.
sub(pattern,repl,string,count=0,flags=0) | |
# pattern: 正则模型 | |
# repl : 要替换的字符串或可执行对象 | |
# string : 要匹配的字符串 | |
# count : 指定匹配个数 | |
# flags : 匹配模式 | |
"hello alex bcd abcd lge acd 19" | origin =|
"a[a-z]+","999999",origin,1) #匹配以a开头则字串,并替换成9999,替换1次 | re.sub(|
'hello 999999 bcd abcd lge acd 19' | |
"a[a-z]+","999999",origin,2) #匹配以a开头则字串,并替换成9999,替换2次 | re.sub(|
'hello 999999 bcd 999999 lge acd 19' |
regex.split() 字符串切割函数,用来实现对指定字符串的分割工作,根据正则匹配分割字符串.
split(pattern,string,maxsplit=0,flags=0) | |
# pattern: 正则模型 | |
# string : 要匹配的字符串 | |
# maxsplit:指定分割个数 | |
# flags : 匹配模式 | |
>>> origin = "hello alex bcd abcd lge acd 19" | |
>>> re.split("alex",origin,1) #无分组切割 | |
['hello ', ' bcd abcd lge acd 19'] | |
>>> re.split("(alex)",origin,1) #有分组,以alex最为分隔符,切割字符串 | |
['hello ', 'alex', ' bcd abcd lge acd 19'] |
单独匹配
compile(r"[A-Z]") | ptr = re.|
"Hello lyshark") | ptr.search(|
<re.Match object; span=(0, 1), match='H'> | |
"Hello lyshark") | ptr.findall(|
['H'] |
re.DOTALL
# 正则表达式默认以单行开始匹配的 | |
import re | |
def re_pattern_syntax(): | |
# .表示任意单一字符 | |
# *表示前一个字符出现>=0次 | |
# re.DOTALL就可以匹配换行符\n,默认是以行来匹配的 | |
print(re.match(r'.*', 'abc\nedf').group()) | |
print('*' * 80) | |
print(re.match(r'.*', 'abc\nedf',re.DOTALL).group()) | |
if __name__ == '__main__': | |
re_pattern_syntax() |
re.MULTILINE
# 正则表达式默认以单行开始匹配的 | |
import re | |
def re_pattern_syntax1(): | |
# ^表示字符串开头(单行) | |
# re.MULTILINE多行匹配字符串开头 | |
print(re.findall(r'^abc', 'abc\nedf')) | |
print('*' * 80) | |
print(re.findall(r'^abc', 'abc\nabc',re.MULTILINE)) | |
def re_pattern_syntax2(): | |
# $表示字符串结尾 | |
# re.MULTILINE表示行的结束 | |
print(re.findall(r'abc\d$', 'abc1\nabc2')) | |
print('*' * 80) | |
print(re.findall(r'abc\d$', 'abc1\nabc2',re.MULTILINE)) | |
if __name__ == '__main__': | |
re_pattern_syntax1() | |
re_pattern_syntax2() |
?非贪婪模式
import re | |
def re_pattern_syntax4(): | |
# greedy贪婪/non-greedy非贪婪,默认的是贪婪的匹配 | |
s = '<H1>title</H1>' | |
print(re.match(r'<.+>', s).group()) #贪婪模式会匹配尽量多的匹配 | |
print(re.match(r'<.+?>', s).group()) #非贪婪模式匹配尽量少的匹配 | |
print(re.match(r'<(.+)>', s).group(1)) | |
print(re.match(r'<(.+?)>', s).group(1)) | |
def re_pattern_syntax5(): | |
# {m}/{m,}/{m,n} | |
print(re.match(r'ab{2,4}', 'abbbbbbb').group()) #贪婪模式尽量匹配多 | |
print(re.match(r'ab{2,4}?', 'abbbbbbb').group()) #非贪婪模式尽量匹配少 | |
print('*' * 80) | |
if __name__ == '__main__': | |
re_pattern_syntax4() | |
re_pattern_syntax5() |
re.I/re.IGNORECASE
import re | |
def re_pattern_flags(): | |
# re.I/re.IGNORECASE | |
print(re.match(r'(Name)\s*:\s*(\w+)','NAME : Joey',re.IGNORECASE).groups()) | |
print('*' * 80) | |
if __name__ == '__main__': | |
re_pattern_syntax_meta_char() |
re.VERBOSE
import re | |
def re_pattern_flags1(): | |
# re.VERBOSE此标识位可以添加注释/re.compile | |
s = 'the number is 20.5' | |
r = re.compile(r''' | |
\d+ # 整数部分 | |
\.? # 小数点,可能包含也可能不包含 | |
\d* # 小数部分,可选 | |
''',re.VERBOSE) | |
print(re.search(r,s).group()) | |
print(r.search(s).group()) | |
print('*' * 80) | |
if __name__ == '__main__': | |
re_pattern_syntax_meta_char1() |