Python 中的 re 模块(Regular Expression 正则表达式)提供各种正则表达式的匹配操作,和 Perl 脚本的正则表达式功能类似,使用这一内嵌于 Python 的语言工具,尽管不能满足所有复杂的匹配情况,但足够在绝大多数情况下能够有效地实现对复杂字符串的分析并提取出相关信息。Python 会将正则表达式转化为字节码,利用 C 语言的匹配引擎进行深度优先的匹配。

元字符

python 支持的正则表达式元字符:

序号 元字符 描述
1 . 匹配任意字符,但不包括换行符
2 ^ 匹配开始位置,多行模式下匹配每一行的开始
3 $ 匹配结束位置,多行模式下匹配每一行的结束
4 * 匹配前一个字符0次到多次
5 + 匹配前一个字符1次到多次
6 ? 匹配前一个字符0次到1次
7 | 逻辑表达式 "或"
8 \ 转义字符,跟在其后的字符将失去其作为特殊元字符的含义
9 {} {m} 匹配前一个字符m次;{m,n} 匹配前一个字符m至n次
10 [] 字符集,一个字符的集合,可匹配其中任意一个字符;[^] 表示取反
11 () 分组,将要匹配的一类字符集放在()组成一个小组

预定义字符

序号 预定义字符 描述
1 \d 匹配数字,相当于 [0-9]
2 \D 匹配非数字,相当于 [^0-9]
3 \s 匹配任意空白字符
4 \S 匹配任意非空字符
5 \w 匹配字母数字及下划线
6 \W 匹配非字母数字及下划线
7 \A 匹配字符串开始
8 \z 匹配字符串结束
9 \Z 匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串
10 \G 匹配最后匹配完成的位置
12 \b 匹配一个单词边界,也就是指单词和空格间的位置
13 \B 匹配非单词边界
14 \n 匹配一个换行符
14 \t 匹配一个制表符
15 \1...\9 匹配第n个分组的内容
  • \b 匹配一个单词边界,也就是指单词和空格间的位置 例如,'er\b' 可以匹配 "never" 中的 'er',但不能匹配 "verb" 中的 'er
  • \B 匹配非单词边界 例如,'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'

字符集[]

序号 字符集 描述
1 [0-9] 匹配数字
2 [a-z] 匹配任何小写字母
3 [A-Z] 匹配任何大写字母
4 [a-zA-Z0-9] 匹配任何字母及数字
5 [^0-9] 匹配除了数字外的字符
6 [^ao] 除了ao字母以外的所有字符

贪婪/非贪婪

贪婪与非贪婪模式影响的是被量词修饰的子表达式的匹配行为,贪婪模式在整个表达式匹配成功的前提下,尽可能多的匹配;而非贪婪模式在整个表达式匹配成功的前提下,尽可能少的匹配。

贪婪模式(默认) 非贪婪模式 描述
* *? 前一个字符0次到多次
+ +? 前一个字符1次到多次
? ?? 前一个字符0次到1次
{m} {m}? 前一个字符m次
{m,n} {m,n}? 前一个字符m次到n次

  • 贪婪模式 在贪婪模式下,正则表达式一般趋向于最大长度匹配,即尽可能多的匹配
>>> import re
>>> exp = "email:opcoder@sina.com,博客:www.opcoder.cn,phone:13607078877"

1. 匹配任意字符0次到多次
>>> re.search('.*', exp).group()
'email:opcoder@sina.com,博客:www.opcoder.cn,phone:13607078877'

2. 匹配任意字符1次到多次
>>> re.search('.+', exp).group()
'email:opcoder@sina.com,博客:www.opcoder.cn,phone:13607078877'

3. 匹配任意字符0次到1
>>> re.search('.?', exp).group()
'e'

4. 匹配 "\d" m次到n次
>>> re.search('\d{3,5}', exp).group()
'13607'

5. 匹配 "[a-z]" m次到n次
>>> re.search('[a-z]{2,10}', exp).group()
'email'
  • 非贪婪模式 非贪婪模式在整个表达式匹配成功的前提下,尽可能少的匹配
>>> import re
>>> exp = "email:opcoder@sina.com,博客:www.opcoder.cn,phone:13607078877"

1. 匹配任意字符0次到多次
>>> re.search('.*?', exp).group()
''

2. 匹配任意字符1次到多次
>>> re.search('.+?', exp).group()
'e'

3. 匹配任意字符0次到1
>>> re.search('.??', exp).group()
''

4. 匹配 "\d" m次到n次
>>> re.search('\d{3,5}?', exp).group()
'136'

5. 匹配 "[a-z]" m次到n次
>>> re.search('[a-z]{2,10}?', exp).group()
'em'

模式(修饰符)

正则表达式可以包含一些可选标志修饰符来控制匹配的模式:

序号 修饰符 描述
1 re.I 忽略大小写
2 re.L 字符集本地化
3 re.M 多行匹配,影响 "^" 和 "$"
4 re.S 使 "." 匹配包括换行符在内的所有字符
5 re.U 根据 Unicode 字符集解析字符
6 re.X 忽略正则表达式中的空白和#号的注释

函数

Python 的 re 模块提供了很多方便的函数使你可以使用正则表达式来操作字符串,每种函数都有它自己的特性和使用场景。

函数目录

序号 函数 描述
1 re.match 从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回None
2 re.search 扫描整个字符串并返回第一个成功的匹配
3 re.compile 编译正则表达式,生成一个正则表达式对象
4 re.findall 找出正则表达式所匹配的所有子串,并返回一个列表
5 re.finditer 找出正则表达式所匹配的所有子串,并返回一个迭代器
6 re.split 根据切分字符串位置,将匹配的字符串分割后返回列表
7 re.sub 替换字符串中的匹配项
8 re.purge 清除缓存中的正则表达式

函数用法

  • re.match re.match 尝试从字符串的起始位置匹配一个模式,如果匹配成功,re.match方法返回一个匹配的对象;如果不是从起始位置匹配成功的话,match()就返回 None

函数语法

re.match(pattern, string, flags=0)

函数参数

参数 描述
pattern 匹配的正则表达式
string 要匹配的源字符串
flags 标志位,用于控制正则表达式的匹配方式,如:re.I 忽略大小写

匹配对象函数

参数 描述
group(num=0) 匹配整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组
groups() 返回一个包含所有小组字符串的元组,从 1 到 所含的小组号

函数示例

>>> import re
>>> exp = "email:opcoder@sina.com,博客:www.opcoder.cn,phone:13607078877"

>>> re.match(r'(.*):(.*)?', exp).group()
'email:opcoder@sina.com,博客:www.opcoder.cn,phone:13607078877'
>>> re.match(r'(.*):(.*)?', exp).group(1)
'email:opcoder@sina.com,博客:www.opcoder.cn,phone'
>>> re.match(r'(.*):(.*)?', exp).group(2)
'13607078877'
  • re.search re.search 扫描整个字符串并返回第一个成功的匹配,失败则返回None;如果字符串中存在多个匹配上的子串,只返回第一个

函数语法

re.search(pattern, string, flags=0)

函数参数

参数 描述
pattern 匹配的正则表达式
string 要匹配的源字符串
flags 标志位,用于控制正则表达式的匹配方式,如:re.I 忽略大小写

匹配对象函数

参数 描述
group(num=0) 匹配整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组
groups() 返回一个包含所有小组字符串的元组,从 1 到 所含的小组号

函数示例

>>> import re
>>> exp = "email:opcoder@sina.com,博客:www.opcoder.cn,phone:13607078877"

>>> re.search(r'[a-z]+', exp).group()
'email'

注: re.match 和 re.search 的区别
re.match 只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回 None;而 re.search 匹配整个字符串,直到找到一个匹配。

>>> import re
>>> exp = "email:opcoder@sina.com,博客:www.opcoder.cn,phone:13607078877"

>>> re.match(r'\d+', exp)
>>> re.search(r'\d+', exp).group()
'13607078877'
  • re.compile compile 函数用于编译正则表达式,生成一个正则表达式对象,供 match() 和 search() 这两个函数使用

函数语法

re.compile(pattern[, flags])

函数参数

参数 描述
pattern 一个字符串形式的正则表达式
flags 标志位,用于控制正则表达式的匹配方式,如:re.I 忽略大小写

函数示例

# 用于匹配至少一个数字
>>> import re

>>> s = "email:opcoder@sina.com,博客:www.opcoder.cn,phone:13607078877"
>>> p = re.compile(r'\d+')

>>> p.match(s)

>>> p.search(s)
<_sre.SRE_Match object; span=(47, 58), match='13607078877'>
  • re.findall 在字符串中找出正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。
    re.match 和 re.search 是匹配一次,而 re.findall 是匹配所有

函数语法

re.findall(string[, pos[, endpos]])

函数参数

参数 描述
string 待匹配的字符串
pos 可选参数,指定字符串的起始位置,默认为 0
endpos 指定字符串的结束位置,默认为字符串的长度

函数示例

>>> import re

>>> p = re.compile(r'\d+')

>>> p.findall(r"baidu.com 123, google.com 456")
['123', '456']
>>> p.findall(r"baidu.com 123, google.com 456", 5, 15)
['123']
  • re.finditer 和 findall 类似,在字符串中找到正则表达式所匹配的所有子串,并把它们作为一个迭代器返回

函数语法

re.finditer(pattern, string, flags=0)

函数参数

参数 描述
pattern 匹配的正则表达式
string 要匹配的字符串
flags 标志位,用于控制正则表达式的匹配方式,如:re.I 忽略大小写

函数示例

>>> [i.group() for i in re.finditer(r"\d+", "12a32bc43jf3")]
['12', '32', '43', '3']
  • re.split split 方法按照能够匹配的子串将字符串分割后返回列表。

函数语法

re.split(pattern, string[, maxsplit=0, flags=0])

函数参数

参数 描述
pattern 匹配的正则表达式
string 要匹配的字符串
maxsplit 分隔次数,maxsplit=1 分隔一次,默认为 0,不限制次数
flags 标志位,用于控制正则表达式的匹配方式,如:re.I 忽略大小写

函数示例

>>> import re

# 按照数字切分
>>> s = '''first 111 line
second 222 line
third 333 line'''
>>> re.split('\d+', s)
['first ', ' line\nsecond ', ' line\nthird ', ' line']

# "\.+" 匹配不到 返回包含自身的列表
>>> re.split('\.+', s, 1)
['first 111 line\nsecond 222 line\nthird 333 line']

# maxsplit 参数
>>> re.split('\d+', s, 1)
['first ', ' line\nsecond 222 line\nthird 333 line']
  • re.sub 替换函数,将正则表达式 pattern 匹配到的字符串替换为 repl 指定的字符串。

函数语法

re.sub(pattern, repl, string, count=0)

函数参数

参数 描述
pattern 匹配的正则表达式
repl 替换的字符串,也可为一个函数
string 要被查找替换的原始字符串
count 模式匹配后替换的最大次数,默认值0表示替换所有的匹配

函数示例

>>> import re

>>> s = "the sum of 7 and 9 is [7+9]."

# 基本用法 将目标替换为固定字符串
>>> re.sub('\[7\+9\]', '16', s)
'the sum of 7 and 9 is 16.'

# 高级用法 使用前面匹配的到的内容 "\1 \2" 代表 pattern 中捕获到的第一个、第二个分组的内容
>>> re.sub('\[(7)\+(9)\]', r'\2\1', s)
'the sum of 7 and 9 is 97.'
  • re.purge 清除缓存中的正则表达式,可能在你需要优化占用内存的时候会用到
>>> re.purge
<function purge at 0x1040fcea0>

re 内置对象用法

  • SRE_Pattern 这个对象是一个编译后的正则表达式,编译后不仅能够复用和提升效率,同时也能够获得一些其他的关于正则表达式的信息
属性 描述
flags 编译时指定的模式
groupindex 以正则表达式中有别名的组的别名为键、以该组对应的编号为值的字典,没有别名的组不包含在内
groups 正则表达式中分组的数量
pattern 编译时用的正则表达式
>>> import re
>>> s = "Hello, opcoder.cn : 2018/08/23"

>>> p = re.compile(r'(?:(?P<name>\w+\.\w+))|(?P<no>\s+\.\w+).*?(\d+), re.X')

>>> print(p.flags)
32
>>> print(p.groupindex)
{'name': 1, 'no': 2}
>>> print(p.groups)
3
>>> print(p.pattern)
(?:(?P<name>\w+\.\w+))|(?P<no>\s+\.\w+).*?(\d+), re.X
  • SRE_Match 这个对象会保存本次匹配的结果,包含很多关于匹配过程以及匹配结果的信息
属性 描述
endpos 本次搜索结束位置索引
lastgroup 本次搜索匹配到的最后一个分组的别名
lastindex 本次搜索匹配到的最后一个分组的索引
pos 本次搜索开始位置索引
re 本次搜索使用的 SRE_Pattern 对象
regs 返回元祖,包含本次搜索匹配到的所有分组的起止位置
string 本次搜索操作的字符串
>>> import re
>>> s = "Hello, opcoder.cn : 2018/08/23"

>>> r = re.search(r', (?P<name>\w+\.\w+).*?(\d+)', s)

>>> r
<_sre.SRE_Match object; span=(5, 24), match=', opcoder.cn : 2018'>

# 本次搜索的结束位置索引
>>> print(r.endpos)
30

# 本次搜索匹配到的最后一个分组的别名,没有则返回None
>>> print(r.lastgroup)
None

# 本次搜索匹配到的最后一个分组的索引
>>> print(r.lastindex)
2

# 本次搜索开始位置索引
>>> print(r.pos)
0

# 本次搜索使用的 SRE_Pattern 对象
>>> print(r.re)
re.compile(', (?P<name>\\w+\\.\\w+).*?(\\d+)')

# 返回元组,包含本次搜索匹配到的所有分组的起止位置 第一个元组为正则表达式匹配范围
>>> print(r.regs)
((5, 24), (7, 17), (20, 24))

# 本次搜索操作的字符串
>>> print(r.string)
Hello, opcoder.cn : 2018/08/23

分组用法

分组就是用一对圆括号 "()" 括起来的正则表达式,匹配出的内容就表示一个分组,从正则表达式的左边开始看,看到的第一个左括号 "(" 表示第一个分组,第二个表示第二个分组,依次类推,需要注意的是,有一个隐含的全局分组(就是0),即整个正则表达式。
分完组以后,要想获得某个分组的内容,直接使用 group(num) 和 groups() 函数获取,当然也可以使用别名来获取。

语法 描述
(...) 分组,默认为捕获,将要匹配的一类字符集放在()组成一个小组
(?:...) 分组的不捕获模式,计算索引时会跳过这个分组
(?P<name>...) 分组的命名模式,取此分组中的内容时可以使用索引也可以使用 name
(?P=name) 分组的引用模式,可在同一个正则表达式中引用前面命名过的正则
  • 普通分组
>>> import re

>>> s = 'http://www.opcoder.cn/search/?q=python'
>>> print(re.search(r'.*q=(.*)', s).group(1))
python
  • 命名分组 命名分组就是给具有默认分组编号的组另外再给一个别名
>>> import re

>>> s = "allenli, www.opcoder.cn : date'2018-07-30'"
>>> res = re.search('(?P<name>\w+\.\w+)(.*?)(\d+)', s)

# 使用别名访问
>>> res.group('name')
'www.opcoder'

# 使用分组访问
>>> res.group()
"www.opcoder.cn : date'2018"
>>> res.group(1)
'www.opcoder'
>>> res.group(2)
".cn : date'"
>>> res.group(3)
'2018'
  • 非捕获分组 有时候可能只是为了把正则表达式分组,而不需要捕获其中的内容,这时候可以使用非捕获分组(仅将正则表达式分组,而不捕获其中的内容)
>>> import re
>>> s = 'age:18,name:Scott'

# 忽略分组
>>> p1 = re.compile('age:(?:\d+),name:(\w+)')
>>> print(re.findall(p1, s))
['Scott']

# 不忽略分组
>>> p2 = re.compile('age:(\d+),name:(\w+)')
>>> print(re.findall(p2, s))
[('18', 'Scott')]

反向引用

捕获组(Expression)在匹配成功时,会将子表达式匹配到的内容,保存到内存中一个以数字为编号的组里,可以简单的认为是对一个局部变量进行了赋值,这时就可以通过反向引用方式,引用这个局部变量的值。一个捕获组(Expression)在匹配成功之前,它的内容可以是不确定的,一旦匹配成功,它的内容就确定了,反向引用的内容也就是确定的了。
反向引用必须要与捕获组一同使用。

  • 例1: 匹配相同字符
import re

>>> s = 'abcdebbcde'
>>> p = re.compile(r'([ab])\1')

>>> print(re.findall(p, s))
['b']

>>> r = re.search(p, s)
>>> r
<_sre.SRE_Match object; span=(5, 7), match='bb'>
>>> r.group()
'bb'

对于正则表达式 "([ab])\1",捕获组中的子表达式 "[ab]" 虽然可以匹配 "a" 或者 "b",但是捕获组一旦匹配成功,反向引用的内容也就确定了。如果捕获组匹配到 "a",那么反向引用也就只能匹配 "a",同理,如果捕获组匹配到的是 "b",那么反向引用也就只能匹配 "b"。由于后面反向引用 "\1" 的限制,要求必须是两个相同的字符,在这里也就是 "aa" 或者 "bb" 才能匹配成功。
正则表达式 "([a-z])\1{2}" 表示连续三个相同的小写字母

  • 例2: 匹配 "ABAB" 型字符串
>>> import re

>>> s = 'abab cdcd efek mmnn'
>>> p = re.compile(r'(\w\w)\1')
>>> print(re.findall(p, s))
['ab', 'cd']

对于正则表达式 "(\w\w)\1",捕获组中的子表达式 "\w\w" 首先会匹配两个字符,如 "ab",此时反向引用也只能匹配 "ab",所以这里只有 "abab" 和 "cdcd" 才能匹配成功。

  • 例3: 匹配 "AABB" 型字符串
>>> import re

>>> s = 'abab cdcd xxyy'
>>> p = re.compile(r'(\w)\1(\w)\2')
>>> print(re.findall(p, s))
[('x', 'y')]

对于正则表达式 "(\w)\1(\w)\2",第一个捕获组中的子表达式 "\w" 首先会匹配一个字符,如 "a",此时反向引用 "\1" 也只能匹配 "a",而第二个捕获组中的子表达式 "\w" 也会匹配一个字符,如 "b",此时反向引用 "\2" 也只能匹配 "b",所以这里只有 "xxyy" 才能匹配成功。

  • 例4: 匹配 "ABBA" 型字符串
import re

s = 'abab toot'
p = re.compile(r'(\w)(\w)\2\1')
print re.findall(p,s)

对于正则表达式 "(\w)(\w)\2\1",第一个捕获组中的子表达式 "\w" 首先会匹配一个字符,如 "a",此时反向引用 "\1" 也只能匹配 "a",而第二个捕获组中的子表达式 "\w" 也会匹配一个字符,如 "b",此时反向引用 "\2" 也只能匹配 "b",所以这里只有 "toot" 才能匹配成功。

环视用法(零宽断言)

环视是一种特殊的正则语法,它匹配的不是字符串,而是位置,其实就是使用正则来说明这个位置的左右应该是什么或者应该不是什么,然后去寻找这个位置。
他们只匹配一个位置,并不消费任何字符

目录

语法 描述 作用
(?=exp) 正向先行断言 匹配 exp 前面的位置,且此位置满足正则 exp
(?!exp) 负向先行断言 匹配 exp 前面的位置,且此位置不满足正则 exp
(?<=exp) 正向后行断言 匹配 exp 后面的位置,且此位置满足正则 exp
(?<!exp) 负向后行断言 匹配 exp 后面的位置,且此位置不满足正则 exp
  • (?=exp) 代表字符串中的一个位置,紧接该位置之后的字符序列能够匹配 exp
    例如 "a regular expression" 这个字符串,要想匹配 regular 中的 re,但不能匹配 expression 中的 re,可以用 "re(?=gular)",该表达式限定了 re 右边的位置,这个位置之后是 gular,但并不消耗 gular 这些字符,将表达式改为 "re(?=gular).",将会匹配 reg,元字符 . 匹配了 g。
>>> import re

>>> exp1 = "a regular expression"
>>> print(re.compile(r're(?=gular).').findall(exp1))
['reg']

>>> exp2 = "I'm singing while you're dancing."
>>> p = re.compile(r'\b\w+(?=ing\b)')
>>> print(re.compile(r'\b\w+(?=ing\b)').findall(exp2))
['sing', 'danc']
>>> print([x + 'ing' for x in re.findall(p, exp2)])
['singing', 'dancing']

说明: "(?=ing\b)" 表示匹配 "ing\b" 位置之前的文本内容,且此位置满足正则 "ing\b" 并且它不会出现在匹配结果中。
  • (?!exp) 代表字符串中的一个位置,紧接该位置之后的字符序列不能匹配 exp
    例如 "regex recent regular expression" 这个字符串,要想匹配除 regex 和 regular 之外的 re,可以用 "re(?!g)\w+",该表达式限定了 re 右边的位置,这个位置后面不是字符 g,负向和正向的区别就在于该位置之后的字符能否匹配括号中的表达式。
>>> import re

>>> exp = "regex recent regular expression"
>>> print(re.compile(r're(?!g)\w+').findall(exp))
['recent', 'ression']
  • (?<=exp) 代表字符串中的一个位置,紧接该位置之前的字符序列能够匹配 exp
    例如 "regex represents regular expression" 这个字符串,有4个单词,要想匹配单词内部的 re,但不匹配单词开头的 re,可以用 "(?<=\w)re\w+",单词内部的 re,在 re 前面应该是一个单词字符。
    之所以叫后行断言,是因为正则表达式引擎在匹配字符串和表达式时,是从前向后逐个扫描字符串中的字符,并判断是否与表达式符合,当在表达式中遇到该断言时,正则表达式引擎需要往字符串前端检测已扫描过的字符,相对于扫描方向是向后的。
>>> import re

>>> exp = "regex represents regular expression"
>>> print(re.compile(r'(?<=\w)re\w+').findall(exp))
['resents', 'ression']
  • ?<!exp) 代表字符串中的一个位置,紧接该位置之前的字符序列不能匹配 exp
    例如 "regex represents regular expression" 这个字符串,要想匹配以 re 开头的字符,可以用 "(?<!\w)re\w+"
>>> import re

>>> exp = "regex represents regular expression"
>>> print(re.compile(r'(?<!\w)re\w+').findall(exp))
['regex', 'represents', 'regular']

用法

  • 匹配 ip地址
>>> ip = "inet addr:172.26.83.189"
>>> print(re.compile(r'(?<=\.)?\d+(?=\.)?').findall(ip))
['172', '26', '83', '189']
  • 匹配存在多种规则约束的字符串 匹配一个长度为4个字符的字符串,该字符串只能由数字、字母或下划线3种字符组成,且必须包含其中的至少两种字符,且不能以下划线或数字开头。
>>> strs = ['_aaa','1aaa','aaaa','a_12','a1','a_123','1234','____']
>>> p = re.compile(r'^(?!_)(?!\d)(?!\d+$)(?![a-zA-Z]+$)\w{4}$')
>>> for s in strs:
...     print(re.findall(p, s))
... 
[]
[]
[]
['a_12']
[]
[]
[]
[]

常用正则校验

手机号码校验

import re

phone_pat = re.compile('^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|166|17[3|6|7]|18[0|1|2|3|5|6|7|8|9])\d{8}$')

while True:
    phone = input('请输入您的手机号:')
    res = re.search(phone_pat, phone)
    if res:
        print('正常手机号')
    else:
        print('不是手机号')

邮箱校验

import re

email_pat = re.compile(r'^[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+){0,4}@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+){0,4}$')

while True:
    email = input('请输入您的邮箱:')
    res = re.search(email_pat, email)
    if res:
        print('正常邮箱')
    else:
        print('不是邮箱')

密码校验

  • 例1: 8-16位任意字符
^[\s\S]{8,16}$
  • 例2: 8-16位字符,至少1个大写字母,1个小写字母和1个数字,其他可以是任意字符
import re

p_passwd = re.compile(r'^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[\s\S]{8,16}$')
while True:
    i_passwd = input('请输入您的密码:')
    res = re.search(p_passwd, i_passwd)
    if res:
        print('True...')
    else:
        print('False...')

说明: "[\s\S]" 中的 "\s " 表示空白符,"\S" 表示非空白符,所以 "[\s\S]" 表示任意字符
  • 例3: 至少8位字符,至少1个字母和1个数字,不能包含特殊字符(非数字和字母)
import re

p_passwd = re.compile(r'^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$')
while True:
    i_passwd = input('请输入您的密码:')
    res = re.search(p_passwd, i_passwd)
    if res:
        print('True...')
    else:
        print('False...')
  • 例4: 至少8位字符,至少1个字母,1个数字和1个特殊字符
import re

p_passwd = re.compile(r'^(?=.*[A-Za-z])(?=.*\d)(?=.*[#$%&\'\"()*+,\-./:;<=>?@[\\\]^_`{|}~])[A-Za-z\d#$%&\'\"()*+,\-./:;<=>?@[\\\]^_`{|}~]{8,}$')

while True:
    i_passwd = input('请输入您的密码:')
    res = re.search(p_passwd, i_passwd)
    if res:
        print('True...')
    else:
        print('False...')
  • 例5: 至少8位字符,至少1个大写字母,1个小写字母和1个数字
import re

p_passwd = re.compile(r'^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,}$')
while True:
    i_passwd = input('请输入您的密码:')
    res = re.search(p_passwd, i_passwd)
    if res:
        print('True...')
    else:
        print('False...')
  • 例6: 至少8位字符,至少1个大写字母,1个小写字母,1个数字和1个特殊字符
import re

p_passwd = re.compile(r'^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[#$%&\'\"()*+,\-./:;<=>?@[\\\]^_`{|}~])[A-Za-z\d#$%&\'\"()*+,\-./:;<=>?@[\\\]^_`{|}~]{8,}')

while True:
    i_passwd = input('请输入您的密码:')
    res = re.search(p_passwd, i_passwd)
    if res:
        print('True...')
    else:
        print('False...')

参考资料

https://www.cnblogs.com/chenxiaoyong/p/6280121.html
https://blog.csdn.net/dnxbjyj/article/details/70946508

原创文章,转载请注明出处:http://www.opcoder.cn/article/7/