文章目录
- 预定义字符
- 元字符
- 重复匹配
- 贪婪和非贪
- 反向引用
- 位置匹配
正则表达式是用来
处理字符串的,重在处理
规则
常用正则
- 年份匹配:
^((19|20)\d{2})$
- 手机号码:
^1[3456789]\d{9}$
- E-mail地址:
^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$
- 网址URL:
http://(/[\w-]+\.)+[\w-]+(/[\w-./?%&=])
re.findall(goal, source)
匹配成功 返回一个列表,列表中有goal
的字符串,找到n次就有n个
匹配失败 返回一个空列表
>>> # 普通字符正则的匹配
>>>
>>> import re
>>> print(re.findall('p', 'python'))
['p']
>>> print(re.findall('python', 'I like python'))
['python']
>>> print(re.findall('o', 'I love python'))
['o', 'o']
>>> print(re.findall('2', '1234567890abcdefg'))
['2']
预定义字符
\d
、\D
、\s
、\S
、\w
、\W
-
\d
:匹配所有数字,0~9
-
\w
:匹配包含下划线字符[a-z|A-Z|0-9|_]
-
\s
:匹配空白符、制表符、换行符[\n \t]
-
\D
:匹配所有非数字,^[0-9]
-
\W
:匹配非正常字符^[a-z|A-Z|0-9|_]
-
\S
:匹配非空白符、制表符、换行符^[\n \t]
-
.
:除了换行符之外所有字符
>>> print(re.findall(r"\d", "1234657890abcdefg"))
['1', '2', '3', '4', '6', '5', '7', '8', '9', '0']
>>> print(re.findall(r"\D", "1234657890abcdefg"))
['a', 'b', 'c', 'd', 'e', 'f', 'g']
>>> print(re.findall(r"\w", "1234657890abcd_%$#efg"))
['1', '2', '3', '4', '6', '5', '7', '8', '9', '0', 'a', 'b', 'c', 'd', '_', 'e', 'f', 'g']
>>> print(re.findall(r"\W", "1234657890abcd_%$#efg"))
['%', '$', '#']
>>> print(re.findall(r"\s", "1234 657\n890ab\tcd_%$#efg"))
[' ', '\n', '\t']
>>> print(re.findall(r"\S", "1234 657\n890ab\tcd_%$#efg"))
['1', '2', '3', '4', '6', '5', '7', '8', '9', '0', 'a', 'b', 'c', 'd', '_', '%', '$', '#', 'e', 'f', 'g']
元字符
[]
、{n}
、^
、-
-
[]
:匹配一个字符,括号内是或者的关系 -
^
:取反 (和这些元字符或\d这些预定义字符一起用才是取反,否则和$一起做位置匹配) -
-
:区间 -
()
:分组,匹配括号内的内容,不要括号两边的内容
# 区间
>>> # 匹配123任意单个字符
>>> print(re.findall(r"[123]", "1234 657\n890ab\tcd_%$#efg"))
['1', '2', '3']
>>> # 匹配单个数字(\d)或 空格换行制表符(\s)
>>> print(re.findall(r"[\d\s]", "1234 657\n890ab\tcd_%$#efg"))
['1', '2', '3', '4', ' ', '6', '5', '7', '\n', '8', '9', '0', '\t']
# 取反
>>> # 匹配单个非数字、非空格换行制表符
>>> print(re.findall(r"[^\d\s]", "1234 657\n890ab\tcd_%$#efg"))
['a', 'b', 'c', 'd', '_', '%', '$', '#', 'e', 'f', 'g']
# 范围
>>> # 匹配单个1-7之间的数字
>>> print(re.findall(r"[1-7]", "1234 657\n890ab\tcd_%$#efg"))
>>> # 匹配单个a-d之间的字母
>>> print(re.findall(r"[a-d]", "1234 657\n890ab\tcd_%$#efg"))
>>> # 匹配单个 1-7 或 a-d 的字符
>>> print(re.findall(r"[1-7a-d]", "1234 657\n890ab\tcd_%$#efg"))
# 分组
>>> # 匹配 左边a右边是a或b或c的两个字符
>>> print(re.findall(r"a[abc]", "aaabacad"))
['aa', 'ab', 'ac']
>>> # 第一步,匹配到['aa', 'ab', 'ac']
>>> # 第二步,不要括号两边的字符,也就是不要a,得到['a', 'b', 'c']
>>> print(re.findall(r"a([abc])", "aaabacad"))
['a', 'b', 'c']
重复匹配
重复匹配默认是贪婪匹配的,会尽量匹配多位
-
{n}
:表示前面的字符重复n次才被匹配成功。a{3}
就匹配出:aaa -
{n,m}
:表示前面的字符至少出现n次,至多出现m次,逗号左右不能有空格,贪婪匹配 -
{n,m}?
:表示前面的字符至少出现n次,至多出现m次,逗号左右不能有空格,非贪婪匹配 -
{n,}
:表示前面的字符至少出现n次,至多出现无穷次
-
?
:相当于{0,1}
,表示前面的字符出现0次或1次 -
+
:相当于{1,}
,表示前面的字符至少出现1次 -
*
:相当于{0,}
,表示前面的字符出现0次或无穷次,贪婪匹配 -
+?
:相当于{1,}?
、{1}
,表示前面的字符至少出现1次,非贪婪匹配 -
*?
:相当于{0,}?
、{0}
,表示前面的字符至少出现0次,非贪婪匹配
-
\
:转义符,在需要匹配上面?+*
几个符号的时候需要加上斜杠\
# {n}
>>> # 贪婪匹配连续3位都是数字
>>> print(re.findall(r"\d{3}", "1234567890abcdefg"))
['123', '456', '789']
>>> # 贪婪匹配连续2位都是正常字符
>>> print(re.findall(r"\w{2}", "12a3456789b0abcdefg"))
['12', 'a3', '45', '67', '89', 'b0', 'ab', 'cd', 'ef']
>>> # 贪婪匹配至少2位至多4位的数字
>>> print(re.findall(r"\d{2,4}", "1234567890abcdefg"))
['1234', '5678']
>>> print(re.findall(r"\d{2,4}", "12a3456789b0abcdefg"))
['12', '3456', '789']
>>> # 非贪婪匹配至少2位至多4位的数字
>>> print(re.findall(r"\d{2,4}?", "12a3456789b0abcdefg"))
['12', '34', '56', '78']
>>> # 贪婪匹配出现至少2位的数字
>>> print(re.findall(r"\d{2,}", "12a3456789b0abcdefg165465165"))
['12', '3456789', '165465165']
# ? + *
>>> # 贪婪匹配0或1个数字,0个也在匹配范围内,所以匹配到非数字的时候是空字符串
>>> print(re.findall(r"\d?", "12a3456789b0abcde_%"))
['1', '2', '', '3', '4', '5', '6', '7', '8', '9', '', '0', '', '', '', '', '', '', '', '']
>>> # 贪婪匹配1或n个数字
>>> print(re.findall(r"\d+", "12a3456789b0abcde_%"))
['12', '3456789', '0']
>>> # 非贪匹配1或n个数字
>>> print(re.findall(r"\d+?", "12a3456789b0abcde_%"))
['1', '2', '3', '4', '5', '6', '7', '8', '9', '0']
>>> # 贪婪匹配1或n个数字
>>> print(re.findall(r"\d*", "1234567890abcdefg"))
['1234567890', '', '', '', '', '', '', '']
>>> # 非贪匹配1或n个数字
>>> print(re.findall(r"\d*?", "1234567890abcdefg"))
['', '1', '', '2', '', '3', '', '4', '', '5', '', '6', '', '7', '', '8', '', '9', '', '0', '', '', '', '', '', '', '', '']
# 转义符
>>> # 匹配a*b
>>> print(re.findall(r"a\*b", "aab*ab*aaa*ba*b*a"))
['a*b', 'a*b']
>>> # 匹配b前面至少出现0次a
>>> print(re.findall(r"a*b", "aab*ab*aaa*ba*b*a"))
['aab', 'ab', 'b', 'b', 'b', 'b']
>>> # 匹配a+b
>>> print(re.findall(r"a\+b", ""))
['a+b']
>>> # 匹配b前面至少出现1次a
print(re.findall(r"a+b", "aab*ab*aa?ba*ba*b*a+b"))
['aab', 'ab']
>>> # 匹配a?b
print(re.findall(r"a\?b", "aab*ab*aa?ba*ba*b*a+b"))
['a?b']
>>> # 匹配b前面至少出现0次至多出现1次a
print(re.findall(r"a?b", "aab*ab*aa?ba*ba*b*a+b"))
['ab', 'ab', 'b', 'b', 'b', 'b']
贪婪和非贪
>>> # 贪婪匹配 d开头d结尾,中间至少出现1位正常字符
>>> print(re.findall(r"d\w+d", "dxxxxxxdxxxxxxd"))
['dxxxxxxdxxxxxxd']
>>> # 非贪匹配 d开头d结尾,中间至少出现1位正常字符
>>> print(re.findall(r"d\w+?d", "dxxxxxxdxxxxxxd"))
['dxxxxd']
>>> html = "<li>Boii</li><li>$18</li><li>男</li><li>i@tcp404.com</li>"
>>> # .是除了换行符以外所有字符
>>> # 贪婪匹配 <li>开头,</li>结尾,中间至少一个非换行符的字符,共1个
>>> print(re.findall(r"<li>.+</li>", html))
['<li>Boii</li><li>$18</li><li>男</li><li>i@tcp404.com</li>']
>>> # 非贪匹配 <li>开头,</li>结尾,中间至少一个非换行符的字符,共3个
>>> print(re.findall(r"<li>.+?</li>", html))
['<li>Boii</li>', '<li>$18</li>', '<li>男</li>', '<li>i@tcp404.com</li>']
>>> # 非贪匹配 <li>开头,</li>结尾,中间至少一个非换行符的字符,且舍去开头结尾,
>>> # 即只取<li></li>中的内容,共3个
>>> print(re.findall(r"<li>(.+?)</li>", html))
['Boii', '$18', '男', 'i@tcp404.com']
反向引用
>>> wordstr = """ 'hello', "python", 'love", "haha' """
# 匹配 开头和结尾都是单引号或双引号,中间至少一个正常字符
>>> print(re.findall(r"['|\"]\w+['|\"]", wordstr))
["'hello'", '"python"', '\'love"', '"haha\'']
# 匹配 开头和结尾都是单引号或双引号,中间至少一个正常字符,舍弃中间
# 即 开头和结尾都是单或双引号,中间至少一个正常字符,然后把开头分一组,结尾分一组,中间无分组被舍弃
>>> print(re.findall(r"('|\")\w+('|\")", wordstr))
[("'", "'"), ('"', '"'), ("'", '"'), ('"', "'")]
# 匹配 开头和结尾都是单引号或双引号,中间至少一个正常字符,开头一组,中间一组,结尾一组,找到一份则组合成一个元组
>>> print(re.findall(r"('|\")(\w+)('|\")", wordstr))
[("'", 'hello', "'"), ('"', 'python', '"'), ("'", 'love', '"'), ('"', 'haha', "'")]
# 匹配 开头是单双引号,中间至少一个正常字符,结尾要与开头对应开头一组那个组相同
# 开头一组,中间一组,结尾一组,找到一份则组合成一个元组
>>> print(re.findall(r"('|\")(\w+)(\1)", wordstr))
[("'", 'hello', "'"), ('"', 'python', '"')]
# 用列表生成式取出每份的1号元素,就得到了内容。
>>> res = re.findall(r"('|\")(\w+)(\1)", wordstr)
>>> li = [x[1] for x in res]
>>> print(li)
['hello', 'python']
# 校验密码,同样的字符不能连续出现3次
>>> print(re.findall(r"(\w)(\1{2,})", "44888813abgggs"))
[('8', '888'), ('g', 'gg')]
# 第一个分组(\w)匹配到是4,进入下一个元组,看到\1替换成4,开始匹配重复:4出现至少2次则匹配成功,后面紧跟着只有一个4,所以匹配失败
# 接着匹配到(\w)是8,进入下一个分组,看到\1替换成8,从第2个8开始匹配重复:8至少出现2次则匹配成功,除去第一个8被第一个分组取走,还剩3个8,匹配成功,这是贪婪匹配,所以会一直吃下去吃到遇见不是8停止,打包成元组
# 接着1匹配失败,3匹配失败,ab都匹配失败
# 接着匹配到(\w)是g,进入下一个分组,看到\1替换成g,从第2个g开始匹配重复:g至少出现2次则匹配成功,除去第一个g被第一个分组取走,还剩2个g,匹配成功,这是贪婪匹配,所以会一直吃下去吃到遇见不是g停止,打包成元组...
res = re.findall(r"(\w)(\1{2,})", "44888813abgggs")
li = [x[0]+x[1] for x in res]
print(li) # ['8888', 'ggg']
位置匹配
-
^
:开头 -
$
:结尾
这两个经常一起使用,用来限定位置
常用于检验手机号、用户名、email地址等
例如匹配手机号
# 手机位数正常的时候可以匹配成功
>>> print(re.findall(r"\d{11}", "13700001111"))
['13700001111']
# 但是手机位数不正常的时候也匹配成功了,所以要加以位置限制
>>> print(re.findall(r"\d{11}", "137000011112233445"))
['13700001111']
>>> print(re.findall(r"^\d{11}$", "13700001111"))
['13700001111']
>>> print(re.findall(r"^\d{11}$", "137000011112233445"))
[]