正则就是字符串处理的瑞士军刀
之前我们是通过if判断来匹配某个字符串,不灵活,太死板了
手机号码匹配,就是有些网站是通过手机号登录的,就是通过这个正则来实现的
电子邮件等应用场景
使用正则就必须使用这个re模块,内置模块,直接导入,不需要下载
re模块核心的函数
1、re.findall(pattern,string,flags=0)
功能:在整个字符串中查找所有匹配项,返回列表(包含所有匹配结果)
场景:批量提取文本中的目标内容(如所有邮箱、所有数字)
参数详解:
-
pattern 就是匹配的内容,要找的这个内容
-
string 匹配的对象,就是从这个对象里面找我需要的内容,必须是字符串
import re
s1 = "pythonqwerpython"
result = re.findall("python",s1)
print(result)
# 输出结果为,返回的是一个列表
['python', 'python']
# 匹配失败,返回的是一个空列表
result = re.findall("qc",s1)
print(result)
# 输出结果为
[]
2、re.match(pattern,string,flags=0)
功能:从字符串开头匹配正则表达式,仅返回第一个结果
– 只会从最开头开启匹配,只管最前面,匹配的内容在中间也会匹配失败,必须在开头
返回值:匹配成功返回的是一个match对象,失败返回none
match对象常用的方法:
-
span(): 返回匹配的起始和结束的索引,也就是匹配到第一个的切片(元组:(start,end))
-
group(): 返回匹配的整个字符串,就是返回匹配的内容
-
groups(n): 返回第n个分组的内容(n从1开始)
s2 = "pythonqwerpython"
result = re.match("python",s2)
print(result)
# 返回的是一个对象
<re.Match object; span=(0, 6), match='python'>
print(result.span())
# 返回第一个匹配到内容的切片
(0,6)
print(result.group())
# 返回匹配到的内容
python
# match是从开头就开始匹配的,非常精确的匹配
s2 = "qwerpython"
result = re.match("python",s2)
print(result)
# 输出结果为,没有匹配到,从开头就开始匹配了
None
3、re.search(pattern,string,flags=0)
功能:在整个字符串查找第一个匹配项(不限制开头了)
返回值:也是返回一个匹配对象,
区别match, match仅匹配开头,search匹配任意位置,就是从头匹配到尾
方法:
-
span()
-
group()
s4 = "pythonqwertpython"
print(re.search("python",s4))
# 返回一个对象
<re.Match object; span=(0, 6), match='python'>
print(re.search("python",s4).group())
# 返回第一个匹配的到的内容
# 和match最不同的方式,从头开始匹配到尾,输出第一次匹配到的内容
s5 = "qwerpython"
print(re.search("python",s5).group())
# 输出结果为
python
上面匹配的内容都是写死的,因此我们需要使用正则来实现这个灵活性
元字符和量词
元字符是正则表达式的语法符号,量词用于控制字符重复次数,结合使用
-
查什么
-
差多少
普通字符(直接匹配)
字母、数字,下划线等普通字符,直接匹配本身
示例;”abc” 匹配 字符串中的”abc”, 123 匹配 123, “_” 匹配 “_”
核心特殊元字符(需要掌握)
元字符
查什么,就是匹配的内容
| 元字符 | 含义 | 示例 |
|---|---|---|
. |
匹配任意单个字符(除了换行符\n) | “a.b”匹配aab,a和b之间任意字符都匹配 |
^ |
匹配字符串开头 | ^abc匹配abc123,不匹配xabc |
$ |
匹配字符串末尾的 | n$ 匹配字符串末尾是n的 |
[] |
匹配括号里面任意一个字符,支持范围[a-z],排除[^a-z] | “[abc]”匹配a,b,c三个字符 |
[^] |
否定字符集,匹配括号外的任意字符 | [^abc] 匹配除了a/b/c外的字符 |
() |
分组:将括号内内容视为整体,可用于提取子串、反向引用 | "(ab)+" 匹配 "ab"/"abab";"(a)(b)" 可通过 \1/\2 引用 |
| |
或:匹配左右任意一个表达式(优先级较低,需配合分组使用) | "a|b" 匹配 "a"/"b";"(ab)|(cd)" 匹配 "ab"/"cd" |
\ |
转义字符:将特殊字符转为普通字符(如 \. 匹配 .) |
"\." 匹配 ".";"\*" 匹配 "*";"\\n" 匹配换行符 |
\d |
等价于[0-9],匹配任意数字 | \d+ 提取字符串中所有数字 |
\D |
等价于[^0-9]匹配非数字 | \D+ 提权字符串非数字字符内容 |
\s |
等价于[\t\n\r\f] 匹配看=空白字符(空格,制表符,换行等) | \s匹配字符串中的空格 |
\S |
等价于[^\t\n\t\f] 匹配非空白字符 | \S 匹配非空白字符 |
\w |
等价于[a-zA-Z0-9_] 匹配字母,数字,下划线 | \w+ 匹配单词(含下划线) |
\b |
– | 匹配单词边界(单词与非单词的分隔) |
\B |
– | 匹配非单词边界 |
元字符案例
p1 = "abcdefgqwer"
print(re.findall(".",p1)) # 在整个字符串中匹配任意的单个字符,也就是全部匹配到了
# 返回结果为
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'q', 'w', 'e', 'r']
# 匹配以ab开头的
s1 = "abcdefabg"
print(re.findall("^ab",s1))
# 返回结果为
['ab']
# 只匹配bg结尾的字符
print(re.findall(r"bg$",s1))
s2 = "asdqweasdaa"
# 匹配 a-f之间的单个字符
print(re.findall("[a-f]",s2))
# 输出结果为
['a', 'd', 'e', 'a', 'd', 'a', 'a']
s3 = "12345sds23"
# 匹配0-9的单个数字
print(re.findall(r"\d",s3))
# 输出结果为
['1', '2', '3', '4', '5', '2', '3']
# 匹配的是数字和字母的单个字符
print(re.findall(r"\w",s3))
# 输出结果为
['1', '2', '3', '4', '5', 's', 'd', 's', '2', '3']
量词(控制重复次数)
上面的元字符就是告诉我们查什么,都是单个字符的,没有需要查多少次,重复的,且都是定死的,下面学习这个量词,就能查清楚了
量词
查多少次
表示匹配前一个字符出现的次数的控制,支持贪婪和非贪婪模式,是正则的核心特性之一
元字符和量词配合使用,效果最佳
默认所有量词都是贪婪,但是量词后面加上一个? 就是非贪婪,拿到第一个立刻停,绝不多拿
| 量词类型 | 语法 | 贪婪/非贪婪 | 含义 | 示例(匹配 a) |
|---|---|---|---|---|
| 零次或多次 | * |
贪婪 | 重复 0 次或多次(优先最多) | a* 匹配 ""/"a"/"aaa" |
| 零次或多次 | *? |
非贪婪 | 重复 0 次或多次(优先最少) | a*? 优先匹配 "" |
| 一次或多次 | + |
贪婪 | 重复 1 次或多次(优先最多) | a+ 匹配 "a"/"aaa" |
| 一次或多次 | +? |
非贪婪 | 重复 1 次或多次(优先最少) | a+? 优先匹配 "a" |
| 零次或一次 | ? |
贪婪 | 重复 0 次或 1 次(优先 1 次) | a? 匹配 ""/"a" |
| 零次或一次 | ?? |
非贪婪 | 重复 0 次或 1 次(优先 0 次) | a?? 优先匹配 "" |
| 精确次数 | {n} |
无(固定) | 必须重复 n 次 | a{3} 匹配 "aaa" |
| 范围次数 | {m,n} |
贪婪 | 重复 m~n 次(优先 n 次) | a{2,4} 匹配 "aa"/"aaa"/"aaaa" |
| 范围次数 | {m,n}? |
非贪婪 | 重复 m~n 次(优先 m 次) | a{2,4}? 优先匹配 "aa" |
| 最少次数 | {m,} |
贪婪 | 至少重复 m 次(无上限,优先最多) | a{2,} 匹配 "aa"/"aaa"… |
| 最多次数 | {,n} |
贪婪 | 最多重复 n 次(0~n 次,优先 n 次) | a{,3} 匹配 ""/"a"/"aaa" |
量词实战
主要就是这些符号的了解,符号的实战
s1 = "anfaagfa"
# 匹配a字符0次或者多次
print(re.findall(r"a*",s1))
# 输出结果为:
['a', '', '', 'aa', '', '', 'a', '']
s1 = "anfaagfa"
# 那么这个*? 就是非贪婪模式,优先最少,那就是重复0次或者1次,多次最后考虑
print(re.findall(r"a*?",s1))
# 输出结果为:
['', 'a', '', '', '', 'a', '', 'a', '', '', '', 'a', '']
s1 = "anfaagfa"
# a+ 表示匹配a字符1次或者多次
print(re.findall("a+",s1))
# 输出结果:
['a', 'aa', 'a']
# a+? 优先最少,优先1次
print(re.findall("a+?",s1))
s1 = "anfaagfa"
# .* 的意思就是匹配0个或者多个任意的字符
print(re.findall(".*",s1))
# 输出结果为,字符串末尾还有一个空字符串,匹配0个
['anfaagfa', '']
s1 = "anfaagfa"
# 匹配a字符0次或者1次
print(re.findall("a?",s1))
# 输出结果为
['a', '', '', 'a', 'a', '', '', 'a', '']
s1 = "anfaagfa"
# 匹配a字符2次,精确匹配
print(re.findall(r"a{2}",s1))
# 输出结果为:
['aa']
s1 = "anfaagaaafaaaa"
# 匹配a字符1到3次
print(re.findall(r"a{1,3}",s1))
# 输出结果为:
['a', 'aa', 'aaa', 'aaa', 'a']
r核心作用就是让字符串里的\表示普通字符,不被当成转义字符
r”\n”,不能让元字符变成普通,还需要\. 变成普通字符
分组
() 就是创建分组的意思
普通捕获分组
s1 = "hellojava,hellopython"
# findall() 函数默认返回分组内的内容
print(re.findall(r"hello(java|python)",s1))
# 输出结果为
['java', 'python']
非捕获分组
# 继续上面的案例
# 如果想要获取到整个字符串的话,在捕获组里面加上?: 就变成了非捕获组,只返回结果,没有分组信息
s1 = "hellojava,hellopython"
print(re.findall(r"hello(?:java|python)",s1))
# 输出结果为
['hellojava', 'hellopython']
贪婪和非贪婪
默认元字符都是贪婪模式,带有?就是非贪婪,尽可能少一点匹配
s2 = "qweaa1231432fsds"
# 数字至少匹配2次,默认是贪婪模式,就是尽可能多的进行匹配
print(re.findall(r"\d{2,}",s2))
# 输出结果为:
['1231432']
s3 = "aa1212"
print(re.findall(r"aa\d*",s3))
# 输出结果为:
['aa1212']
# 关闭贪婪模式,尽可能少匹配数字
print(re.findall(r"aa\d?",s3))
# 输出结果为:
['aa1']
案例
匹配qq邮箱
qq邮箱规则:
-
第一个是数字1-9
-
4-11位
-
@qq.com结尾,写死就行了
s5 = input('请输入qq邮箱:')
print(re.findall(r"^[1-9]\d{4,11}@qq\.com$",s5))
总结
re模块函数总结
re.findall 在整个字符串找到所有匹配的内容,返回一个列表
re.search 在整个字符串找到第一次匹配的内容,返回一个匹配的对象
re.match 从头就开始匹配,不符合就返回none,匹配成功就返回匹配的对象
文章摘自:https://www.cnblogs.com/qylogs/p/20119955
