正则表达式之Python
一直觉得正则是一个很重要、必须的掌握的知识,但平时用的不太多,即使用也是网上或者代码库里copy过来,其实并没有掌握,今天终于准备整理一下。
认识正则
正则表达式又称规则表达式,计算机科学的一个概念。它描述了一种字符串匹配的模式(pattern),可以用来检查一个串是否含有某种子串、将匹配的子串替换或者从某个串中取出符合某个条件的子串等。一句话用来检索、替换那些符合某个模式(规则)的文本。
许多程序设计语言都支持利用正则表达式进行字符串操作。例如,在Perl中就内建了一个功能强大的正则表达式引擎。正则表达式这个概念最初是由Unix中的工具软件(例如sed和grep)普及开的。正则表达式通常缩写成代码中常简写为regex、regexp或RE。
特点
- 灵活性、逻辑性和功能性非常强
- 可以迅速地用极简单的方式达到字符串的复杂控制
- 对于刚接触的人来说,比较晦涩难懂
使用场景
- 文本或字符串的检索、替换、切割等
- 表单验证(身份证、手机号、邮箱、URL、IP、姓名等的匹配验证)
- 爬取项目里特定内容的提取
python里如何使用正则
Python 自1.5版本起增加了re 模块,它提供 Perl 风格的正则表达式模式。
re 模块使 Python 语言拥有全部的正则表达式功能。
compile 函数根据一个模式字符串和可选的标志参数生成一个正则表达式对象。该对象拥有一系列方法用于正则表达式匹配和替换。
一些特殊字符及语法
^
- 放在首位:匹配输入字符串的开始位置
# 字符串开始位置与匹配规则符合就匹配 a = re.findall("^阿蓝", "阿蓝的小窝http://boringblue.cn") b = re.findall("^阿蓝", "这里是阿蓝的小窝http://boringblue.cn") print(a,b) # 输出:['阿蓝'] []
- 放在中括号里:取反
[^]:匹配除了中括号中的所有内容a = re.findall("[^a-z]", "阿蓝的小窝 ://xx.x") # 反取,匹配出除字母外的字符 b = re.findall("[^\u4E00-\u9FA5]", "阿蓝的小窝 ://xx.x") # 反取,匹配出除汉字外的字符 c = re.findall("[^阿蓝]", "阿蓝的小窝 ://xx.x") # 反取,匹配出除“阿”、“蓝”外的字符 d = re.findall("[^:/. ]", "阿蓝的小窝 ://xx.x") # 反取,匹配出除“:”、“/”、“.”、“ ”外的字符 print(a,b,c,d) # 输出: # ['阿', '蓝', '的', '小', '窝', ' ', ':', '/', '/', '.'] # [' ', ':', '/', '/', 'x', 'x', '.', 'x'] # ['的', '小', '窝', ' ', ':', '/', '/', 'x', 'x', '.', 'x'] # ['阿', '蓝', '的', '小', '窝', 'x', 'x', 'x']
- 放在首位:匹配输入字符串的开始位置
$
匹配一个字符串的结束a = re.findall("cn$", "阿蓝的小窝http://boringblue.cn") b = re.findall("阿蓝$", "阿蓝的小窝http://boringblue.cn") print(a,b) # 输出:['cn'] []
.
匹配除 “\n” 之外的任何单个字符。要匹配包括 ‘\n’ 在内的任何字符,请使用象 ‘[.\n]’ 的模式*
表示匹配量词之前的字符出现0次或者多次
贪婪匹配:以开头
非贪婪匹配:以结尾# 非贪婪匹配 a = re.findall(".*小窝", "蓝阿蓝") b = re.findall(".*小窝", "蓝阿蓝的小窝阿蓝") # 贪婪匹配 c = re.findall("阿蓝*", "蓝阿蓝的小窝阿蓝") d = re.findall(".*", "蓝阿蓝") print(a,b,c,d) # 输出:[] ['蓝阿蓝的小窝'] ['阿蓝', '阿蓝'] ['蓝阿蓝', '']
+
匹配量词之前的字符出现1次或者多次a = re.findall(".+小窝", "蓝阿蓝") b = re.findall(".+小窝", "蓝阿蓝的小窝阿蓝") c = re.findall("阿蓝+", "蓝阿蓝的小窝阿蓝") d = re.findall(".+", "蓝阿蓝") print(a,b,c,d) # 输出:[] ['蓝阿蓝的小窝'] ['阿蓝', '阿蓝'] ['蓝阿蓝']
?
匹配这个元符号之前的字符出现0次或者1次。及表示该符号前的字符可有可无时a = re.findall("Bufff?", "蓝阿蓝的小窝是蓝Buff Bufff") b = re.findall("阿蓝?蓝", "蓝阿蓝蓝的小窝是蓝Buff 阿蓝") c = re.findall("阿蓝蓝?", "蓝阿蓝的小窝是蓝Buff 阿蓝蓝") d = re.findall("窝是?蓝Buff", "蓝阿蓝的小窝是蓝Buff BoringBlue") e = re.findall("窝是?Buff", "蓝阿蓝的小窝是蓝Buff BoringBlue") print(a,b,c,d,e) # 输出:['Buff', 'Bufff'] ['阿蓝蓝', '阿蓝'] ['阿蓝', '阿蓝蓝'] ['窝是蓝Buff'] []
{}
匹配次数范围a = re.findall("Buf{3}", "蓝阿蓝的小窝是蓝Buff Bufff") # 前面一个字符匹配3次 b = re.findall("阿蓝{0,3}", "蓝阿蓝蓝的小窝是蓝Buff 阿蓝") # 前面一个字符匹配0~3次 c = re.findall("蓝{1,}阿蓝", "蓝阿蓝的小窝是蓝Buff 阿蓝") # 等同于 (+,)匹配一次或多次 (0,)匹配0次或多次 print(a,b,c) # 输出:['Bufff'] ['阿蓝蓝', '阿蓝'] ['蓝阿蓝']
[]
匹配字符集,匹配[]里的任意一个字符。字符集中的字符可以逐个列出,也可以给出范围,如[abc]或[a-c]。[^abc]表示取反,即非abc。所有特殊字符在字符集中都失去其原有的特殊含义。用\反斜杠转义恢复特殊字符的特殊含义。a = re.findall("B[Buf]f", "蓝阿蓝的小窝是蓝Buff Bufff") b = re.findall("[蓝Buff]的小窝", "蓝阿蓝的小窝=蓝Buff的小窝") c = re.findall("蓝[什么]蓝", "蓝阿蓝的小窝是蓝Buff 阿蓝") print(a,b,c) # 输出: ['Buf', 'Buf'] ['蓝的小窝', 'f的小窝'] []
()
|
或a = re.findall("蓝|阿", "2022年阿蓝666!") print(a) # 输出:['阿', '蓝']
\d
匹配任何十进制数,相当于[0-9]a = re.findall("\d", "2022年的蓝buff666") print(a) # 输出:['2', '0', '2', '2', '6', '6', '6']
\d+
匹配一位或者多位数的数字时用a = re.findall("\d+", "2022年的蓝buff666") print(a) # 输出:['2022', '666']
\D
匹配任何非数字字符,相当于[^0-9]a = re.findall("\D", "2022年的蓝buff666") print(a) # 输出:['年', '的', '蓝', 'b', 'u', 'f', 'f']
\s
匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]a = re.findall("\s", "2022年 蓝buff\n666! ") print(a) # 输出:[' ', '\n', ' ', ' ', ' ']
\S
匹配任何非空白字符。等价于 [^ \f\n\r\t\v]a = re.findall("\S", "2022年 蓝buff\n666! ") print(a) # 输出:['2', '0', '2', '2', '年', '蓝', 'b', 'u', 'f', 'f', '6', '6', '6', '!']
\w
匹配包括下划线的任何单词字符。等价于’[A-Za-z0-9_]’
python3里re默认支持的是unicode字符集,所以还可以匹配中文。\W
匹配任何非单词字符。等价于 ‘[^A-Za-z0-9_]’
常用正则表达式处理函数
re.compile(pattern, flags=0)
将正则表达式的样式编译为一个 正则表达式对象 (正则对象),可以用于匹配。
这个表达式的行为可以通过指定 标记 的值来改变。值可以是以下任意变量,可以通过位的OR操作来结合( | 操作符)。序列
prog = re.compile(pattern)
result = prog.match(string)等价于
result = re.match(pattern, string)
如果需要多次使用这个正则表达式的话,使用 re.compile() 和保存这个正则对象以便复用,可以让程序更加高效。
注解 通过 re.compile() 编译后的样式,和模块级的函数会被缓存, 所以少数的正则表达式使用无需考虑编译的问题。re.match(pattern, string, flags=0)
如果 string 开始的0或者多个字符匹配到了正则表达式样式,就返回一个相应的 匹配对象 。 如果没有匹配,就返回 None ;注意它跟零长度匹配是不同的。
注意即便是 MULTILINE 多行模式, re.match() 也只匹配字符串的开始位置,而不匹配每行开始。- pattern: 正则模型
- string : 要匹配的字符串
- falgs : 匹配模式
注意:match()函数 与 search()函数基本是一样的功能,不一样的就是match()匹配字符串开始位置的一个符合规则的字符串,search()是在字符串全局匹配第一个合规则的字符串
re.search(pattern, string, flags=0)
扫描整个 字符串 找到匹配样式的第一个位置,并返回一个相应的 匹配对象。如果没有匹配,就返回一个 None ; 注意这和找到一个零长度匹配是不同的re.split(pattern, string, maxsplit=0, flags=0)
- pattern: 正则模型
- string : 要匹配的字符串
- maxsplit:指定分割个数
- flags : 匹配模式
re.findall(pattern, string, flags=0)
浏览全部字符串,匹配所有合规则的字符串,匹配到的字符串放到一个列表中,未匹配成功返回空列表
注意:一旦匹配成,再次匹配,是从前一次匹配成功的,后面一位开始的,也可以理解为匹配成功的字符串,不在参与下次匹配re.sub(pattern, repl, string, count=0, flags=0)
re.subn(pattern, repl, string, count=0, flags=0)
re.escape(pattern)
一些常用的正则
验证 | 正则 |
---|---|
验证手机号 | 1[3,4,5,7,8]\d{9} |
验证邮箱 | ^\w+([-+.]\w+)*@\w+([-.]\w+).\w+([-.]\w+)$ |
验证IP地址 | \d+.\d+.\d+.\d+ |
验证姓名(中文、英文、“·”) | ^[\u4E00-\u9FA5A-Za-z·]+$ |
验证网址 | [a-zA-z]+://[^\s]* |
验证身份证号码 | /^[1-9]\d{7}((0\d) | (1[0-2]))(([0 | 1 | 2]\d) | 3[0-1])\d{3}$ | ^[1-9]\d{5}[1-9]\d{3}((0\d) | (1[0-2]))(([0 | 1 | 2]\d) | 3[0-1])\d{3}([0-9] | X)$ |