图|一张顾巷
文|一张顾巷
门径初窥
//正则:交个朋友?// 鸽 ?了大家好久的正则,今天终于来啦~~ 朋友:谁是正则啊? 那就由正则本人来一个官方的自我介绍。(旁白) 正则: 俺大名, 正则表达式;洋 名, Regular Expression。是一个根据「 特定语法结构编写 」 的正经字符串 。 朋友:那你有啥本领呀? 正则:字符串的检索、替换及匹配验证都离不开我~ 朋友:耍个瞧瞧噻。 正则:嗐,说来就来,您瞧好,咱先来个简单的, 从下述字符串中提取手机号码兔子小白将写了13451817705的字条悄咪咪藏好
朋友:要怎么提取?遍历字符串一个个字符判断?
正则:duck不必,只需下述一串字符串:
"(?
朋友:
正则:交个朋友
?
//在线小工具分享//
随手打开一个在线正则测试工具,复制粘贴:
https://tool.oschina.net/regex/
点击测试匹配后,可以看到手机号码已被提取出来了,强大如斯,看不懂上述表达式?没关系,往下看Python中正则的详细用法。
明其所以
//re模块// Python中内置re模块用来处理正则表达式,上述在线测试的例子可以写成Python代码:import rereg_string = '兔子小白将写了13451817705的字条悄咪咪藏好'reg = '(?result = re.search(reg, reg_string)print(result)# 输出:# <_sre.sre_match object span="(7," match="13451817705">
上述用到的search()函数是re模块提供的正则匹配函数,一一介绍下re模块提供的几个常用函数~
//常用函数//
匹配
re.match(pattern, string, flags=0)
尝试从字符串的开头进行匹配,匹配成功返回匹配对象,否则返回None re.search (pattern, string, flags=0) 扫描整个字符串,返回第一个匹配对象,否则返回None检索与替换
re.findall(pattern, string, flags=0)
扫描整个字符串,匹配所有能匹配的对象,以列表形式返回
re.finditer(pattern, string, flags=0)
同findall,匹配所有能匹配的对象,但是是以迭代器形式返回
re.sub(pattern, repl, string, count=0, flags=0)
将匹配的字符串替换为其他字符串,count为替换的最大次数,默认为0,替换所有
re.split(pattern, string, maxsplit=0, flags=0)
将匹配的字符串进行分割,返回列表,maxsplit为分割的最大次数,默认为0,分割所有
编译Pattern对象
对于多次用的正则表达式,可调用compile()函数将正则表达式编译成Pattern对象,调用时直接Pattern对象.xxx即可,以此提高复用性
flags修饰符
在调用这些常用函数时,可传入flags参数(标志位修饰符),来控制匹配模式,有下表这些可供选择,如果想同时选择多个使用运算符"|"进行连接,比如:re.I|re.M
修饰符 | 描述 |
re.I | IGNORECASE → 忽略大小写 |
re.M | MULTILINE → 多行匹配,影响^和$ |
re.S | DOTALL → 使.匹配包括换行在内的所有字符 |
re.X | VERBOSE → 忽略空白和注释,并允许使用'#'来引导一个注释 |
re.U | UNICODE → 根据Unicode字符集解析字符,影响\w、\W、\b和\B |
re.L | LOCALE → 做本地化识别(locale-aware)匹配 |
正则语法详解
/ /'r'知多少 // 用于告知编译器这个string是raw string(原始字符串), 不要转义反斜杠 ,比如r'\n'是两个字符:反斜杠+n,而不是换行! / /转义少不了 // 当遇到用于正则匹配模式的特殊字符时,在前面加 反斜线转义 一下即可,比如\.,\(,\)等。//字符规则//
字符 | 作用 |
. | 匹配任意一个字符(除\n外) |
[...] | 匹配[]中列举的字符 |
[^...] | 匹配不在[]中列举的字符 |
\d | 匹配数字,0-9 |
\D | 匹配非数字 |
\s | 匹配空白,即空白与tab缩进 |
\S | 匹配非空白 |
\w | 匹配字母数字或下划线,a-z,A-Z,0-9,_ |
\W | 匹配非字母数字或下划线 |
- | 匹配范围,如a-f |
//边界规则//
字符 | 作用 |
^ | 行开始 |
$ | 行结束 |
\b | 单词边界,即单词和空格间的位置,如'er\b'可匹配'never'中的'er',但不能匹配'verb'中的'er' |
\B | 匹配非单词边界 |
\A | 匹配字符串开头 |
\Z | 匹配字符串结尾,如果有换行,只匹配到换行前的结束字符串 |
\z | 匹配字符串结尾,如果有换行,会连换行符也匹配 |
//分组//
有时我们需要的可能是匹配字符串中的一部分内容,可以进行分组,使用括号()包裹,比如:从匹配的字符串中提取出区号和本地号码 → ^(\d{3})-(\d{3,8})$,具体规则如下表所示:
字符 | 作用 |
l | 匹配左右任意一个表达式 |
(re) | 匹配括号内的表达式,也表示一个组 |
(?:re) | 同上,但不表示一个组 |
(?=re)→前向肯定断言,仅当子表达式在此位置的右侧匹配时才继续匹配,如:ok(?=fu) ,与以fu结尾的ok实例匹配。
(?!re)→前向否定断言,仅当子表达式不在此位置的右侧匹配时才继续匹配,如:(?!fu) 与不以fu结尾的实例匹配,所以与okfu不匹配。
(?<=re)→后向肯定断言,仅当子表达式在此位置的左侧匹配时才继续匹配,如:(?=ok)fu 与跟在ok后的fu实例匹配。
(?不以ok开头的实例匹配,所以与okfu不匹配。
re中的group()函数也可以获取带每个匹配的分组内容:
import rereg_pattern = re.match(r'^(\d{4})-(\d{3,8})$', '0756-1234567')print(reg_pattern.group())print(reg_pattern.group(0))print(reg_pattern.group(1))print(reg_pattern.group(2))# 输出:# 0756-1234567# 0756-1234567# 0756# 1234567
此外,还有四个常用函数:
groups():从group(1)开始往后的所有值,返回一个元组
start():返回匹配的开始位置
end():返回匹配的结束位置
span():返回一个元组,表示匹配位置(开始,结束)
//贪婪匹配和非贪婪匹配//
正则匹配默认是贪婪匹配,即匹配尽可能多的字符。若需要匹配符合表达式尽可能少的字符串,则可以合理使用” ?“,采用非贪婪匹配。
import rere.match(r'^(\d+)(0*)$','12345000').groups()# 原意是想得到('12345', '000')这样的结果的,但输出的却是:('12345000', '')# 由于贪婪匹配,直接把后面的0都给匹配了,结果0*只能匹配空字符串了,# 若果想尽可能少的匹配,可在\d+后加上一个问号?,采用非贪婪匹配re.match(r'^(\d+?)(0*)$','12345000').groups()# 输出结果:('12345', '000')
//常用正则收录//
参考https://juejin.cn/post/6844904182835757064# 火车车次[GCDZTSPKXLY1-9]\d{1,4}# 手机机身码(IMEI)\d{15,17}# 必须带端口号的网址(或ip)((ht|f)tps?:\/\/)?[\w-]+(\.[\w-]+)+:\d{1,5}\/?# 统一社会信用代码[0-9A-HJ-NPQRTUWXY]{2}\d{6}[0-9A-HJ-NPQRTUWXY]{10}# 子网掩码 (?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])(?:\.(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])){3}# 网址(url,支持端口和"?+参数"和"#+参数)((ht|f)tps?://)?[\w-]+(\.[\w-]+)+([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?# 24小时制时间(HH:mm:ss)(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d# 12小时制时间(hh:mm:ss)(?:1[0-2]|0?[1-9]):[0-5]\d:[0-5]\d# date(日期)\d{4}(-)(1[0-2]|0?\d)\1([0-2]\d|\d|30|31)# email(邮箱)(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))# 匹配连续重复的字符(.)\1+# 银行卡号(10到30位, 覆盖对公/私账户, 参考微信支付)[1-9]\d{9,29}# 手机号(mobile phone)中国(严谨), 根据工信部2019年最新公布的手机号段(?:(?:\+|00)86)?1(?:(?:3[\d])|(?:4[5-7|9])|(?:5[0-3|5-9])|(?:6[5-7])|(?:7[0-8])|(?:8[\d])|(?:9[1|8|9]))\d{8}
虽迟但到,希望对你们有帮助,比心心~