目录
前言
正则表达式是一个可以筛选存在某些规律的规则,在php中替换函数会经常使用正则。比如需要从很长的一个字符串里筛选电话号码、身份证号码这类存在某些规律的字符串时,使用正则会非常方便。批量处理文本数据时也需要使用正则,python通过标准库中的re模块来支持正则表达式操作。
正则表达式的强大之处在于引入特殊字符来定义字符集、匹配子组和重复模式。由于python的这些特殊符号,使正则表达式可以匹配字符串集合,不仅仅局限于单个字符串。
1. 正则表达式简单语法速记
表示法 | 描述 | 正则表达式实例 | 说明 |
re1|re2 | 匹配正则表达式re1或者re2 | a|b | 可能匹配字符a或者b |
. | 匹配任意字符(除了\n以外) | b.b | 可以匹配bbb\b#t\b1t等 |
^ | 匹配字符串起始的部分 | ^a | 可以匹配以a开头的字符串 |
$ | 匹配字符串结束 | .sh$ | 可以匹配以.sh解为的字符串 |
* | 匹配0次或者多次前面出现的正则表达式 | [a-z]* | 可以匹配0次或者多次出现的a-z的字符串 |
+ | 匹配1次或者多次的正则表达式 | [a-z]+ | 可以匹配1次或者多次出现在前面的字符串 |
? | 匹配0次或者1次出现在前面的字符串 | foo? | foo可能匹配0次或者1次 |
{N} | 匹配N次前面出现的正则表达式 | [0-9]{3} | 可以根据前面的正则表达式进行三次匹配 |
{N,} | 至少匹配N次前面出现的正则 | [0-9]{3,} | 可以根据前面的正则表达式至少进行三次匹配 |
{N,M} | 匹配N~M次前面出现的正则表达式 | [0-9]{1,3} | 可以根据前面的正则表达式进行1-3次匹配 |
[aeiou] | 匹配来自字符集的任意单一字符 | [aeiou] | 可以匹配aeiou任意字符 |
[..x-y..] | 匹配x~y范围中的任意单一字符 | [0-9] | 匹配0-9范围的任意一个数字 |
[^....] | 不匹配在此字符集中出现的任何一个字符(包括范围字符) | [^aeiou],[^0-9] | 匹配除了aeiou,0-9的字符 |
(*|+|?|{})? | 匹配前面频繁出现/重复出现符号的非贪婪版本 | a.*?b a.*b | 优先匹配abb 优先匹配ababaab |
(....) | 匹配封闭的正则表达式,然后另存为子组 | ([0-9]{3})?,f(oo|u)bar | 括号内的优先匹配 |
\d | 匹配任何十进制数字,不匹配任何非数值型的数字 | data\d.txt | 匹配data[0-9].txt |
\D | 匹配非数字 | \d\D | 可以匹配9a、3#、0F等 |
\w | 匹配任何字母数字字符除# | b\wt | 可以匹配bat / b1t / b_t等但不能匹配b#t |
\W | 匹配非字母数字下划线 | b\Wt | 可以匹配b#t / b@t等 但不能匹配but / b1t / b_t等 |
\s | 匹配空白字符(包括\r、\n、\t等) | hi\shello | 可匹配hi hello |
\S | 匹配任意非空白字符 | hi\Shello | 可以匹配love#you等 但不能匹配love you |
\b | 匹配字符集边界 | \bThe\b | |
\B | 匹配非字符集边界 | \Bio\B | |
\N | 匹配已保存的子组 | \b(\w+)\b\s+\1\b | 匹配重复的单词 \1表示分组1匹配的文本 |
\ | 可以理解为单纯的转移符 | \*,\.\\ | 会匹配*,.,\ |
(?iLmsux) | 在正则表达式中嵌入一条特殊"标记参数" | (?x) | |
(?:exp) | 匹配exp,不保存匹配的文本,也不给此组分配组号 | (?:\w+\.)* | 这个我也没弄清楚 |
(?<name>exp) | 匹配exp并保存到名为name的组中 | (?<word>\w+) | 匹配任何字母数字保存到组名word中 |
(?=exp) | 匹配exp前面的位置 | (?=data) | 获取在data前面的字符集 |
(?#) | 表示注释,内容会被忽略 | (?#comment) | |
(?<=exp) | 匹配exp后面的字符集 | ||
(?!exp) | 匹配后面不是exp的字符集 | ||
(?<!exp) | 匹配前面不是exp的字符集 |
2. Python对正则的支持
在python中常使用re模块支持正则表达式的相关操作,re模块提供常用的函数和方法,这些函数和已经编译的正则表达式对象和正则匹配对象的方法同名并具有相同的功能,提供re模块的核心函数。
函数 | 说明 |
compile(pattren, flags=0) | 编译正则表达式返回正则表达式对象 |
match(pattern, string, flags=0) | 用正则表达式匹配字符串(成功则返回匹配对象 否则返回None) |
search(pattern, string, flags=0) | 搜索字符串中第一次出现正则表达式的模式(成功返回匹配对象 否则返回None) |
split(pattern, string, maxsplit=0, flags=0) | 用正则表达式指定的模式分隔符拆分字符串(返回列表) |
sub(pattern, repl, string, count=0, flags=0) | 用指定的字符串替换原来字符串中与正则表达式匹配的模式可以用count来指定替换的次数 |
fullmatch(pattern, string, flags=0) | match函数的完全匹配(从字符串开头到结尾)版本 |
findall(pattern, string, flags=0) | 查找字符串所有与正则表达式匹配的模式(返回字符串列表) |
finditer(pattern, string, flags=0) | 查找字符串所有与正则表达式匹配的模式(返回一个迭代器) |
purge() | 清除隐式编译的正则表达式的缓存 |
re.l / re.IGNORECASE | 忽略大小写匹配标记 |
re.M / re.MULTILINE | 多行匹配标记 |
3. 练习
例1. 验证用户输入的用户名和QQ号是否有效
"""
根据输入的用户名和QQ号来验证有效信息
要求:用户名由大小写字符,数字或下划线组成长度在6~20个字符之间
QQ号是5~12的数字且首位不能为0
"""
import re
def main():
username = input('请输入用户名:')
qq = input('请输入QQ号:')
username = re.match(r'^[0-9a-zA-z_]{6,20}$', username)
if not username:
print('请输入有效的用户名')
qq = re.match(r'^[1-9]\d{5,12}$', qq)
if not qq:
print('请输入正确的qq号')
if username and qq:
print('输入正确')
if __name__ == '__main__':
main()
注意:在书写正则表达式规则的时候在前面添加了一个r,这是“原始字符串”的写法,原始字符串的意思是每个特殊符号都是原始的意义。因为正则表达式中有很多元字符需要进行转义如果不使用原始字符串就需要使用反斜杠来转义。
例2. 从一段文字内截取国内手机号码
"""
电信:133/153/180/181/189/177
联通:130/131/132/155/156/185/186/145/176
移动:134/135/136/137/138/139/150/151/152/157/158/159/182/183/184/187/188/147/178
"""
import re
def main():
pattern = re.compile(r'(?<=\D)(1[38]\d{9}|14[57]\d{8}|15[0-35-9]\d{8}|17[678]\d{8})(?=\D)')
sentence = '''福建按大家分厘卡JFK的肌肤户回复哈就,电话号码13023188119,
其余120的倾听下回分解,
'''
mylist = re.findall(pattern, sentence)
print(mylist)
for temp in pattern.finditer(sentence):
print(temp.group())
m = pattern.search(sentence)
while m:
print(m.group())
m = pattern.search(sentence, m.end())
if __name__ =='__main__':
main()
例3. 替换
经常玩英雄联盟的人没跟队友打过口水仗那就说明你不适合召唤师峡谷,呕!祖安。
import re
def main():
sentence = 'fuck 有 ....。你是你妈的......,傻逼,操......。'
purified = re.sub('fuck|mother|[曹操]|[傻逼]|妈', '*', sentence, flags=re.IGNORECASE)
print(purified)
if __name__ == '__main__':
main()
筛选结果:
补充:re模块的正则表达式相关函数中都有一个flags参数,它表示正则表达式的匹配标记,可以通过标记来指定匹配过程对内容的限定条件,比如(忽略大小、进行多行匹配、是否显示调试信息等)。如果需要为flags参数指定多个值,可以使用按位或运算符(|)进行叠加。
4. 拆分
import re
def main():
poem = '窗前明月光,疑是地上霜。举头望明月,低头思故乡。'
sentence_list = re.split(r'[,。, .]', poem)
while '' in sentence_list:
sentence_list.remove('')
print(sentence_list)
if __name__ == '__main__':
main()