正则表达式
分类
- BRE: grep sed vi
- ERE: egrep / grep -E / sed -r
- PCRE: python re
元字符
- . : 匹配除换行符意外的任意字符
- [abc]: 字符集合,一次只能匹配一个字符,匹配a、b、c
- [^abc]: 字符集合,不是a/b/c
- [a-z]: 小写字符
- [^a-z]: 不是小写
- \b: 单词边界
- \B: 不匹配单词边界
- \d: [0-9]匹配1个数字
- \D: [^0-9]不匹配1个数字
- \s: 匹配一个空白字符.包括制表符、换行符、空格
- \S: 非空白字符
- \w: 匹配[0-9a-zA-z],包括中文
- \W: w之外的字符
-
单行模式
. 匹配所有字符,包括换行符
$ 整个字符串的结尾
^ 整个字符串的开头 -
多行模式
. 除换行符的所有字符
$ 行尾
^ 行首
转义
使用 \ 转义,反斜杠本身\
\r \n 转义后代表回车、换行
重复-初级
- * 0次或者多次
- + 至少一次
- ? 表示前面的正则表达式重复0次或者1次
- {n} 重复固定的n次
- {n,} 至少重复n次
- {n,m} 重复n到m次;
捕获、分组
x|y 匹配x或者y; \b(a|b)\w+ 以a或者b开头的单词
捕获/分组(pattern): 捕获或会自动分配组号,自动从1开始,0表示捕获的全长
\数字 匹配对应的分组,刚好取到前面匹配到的内容;
(?:pattern) 不被捕获,不要分组,保留‘或’;\b(?:a|b)\w+
(?<name>exp) 通过name访问分组、Python语法:(?P<nane>exp)
断言
判断一件事一定发生、一定不发生,一定是一定不是
(?=exp) f(?=oo) f后面一定有oo出现;
(?<=exp) (?<=f)ood ood前面一定在前面有t
(?!exp) 一定没有
(?<!exp) (?<!f)ood ood前面一定没有f;
(?#comment) 添加注释
贪婪与非贪婪
f.*t 默认.* 是贪婪的,到最后一个匹配到的t
f.*?t f.+?t: 尽可能少匹配;
f\w+?t 单词;
f.{1,}?t 取1次;
----
*? 匹配任意次, 尽可能少重复;
+? 匹配至少一次, 尽可能少重复;
?? 匹配0次或者1次, 尽可能少重复;
{n,}? 匹配至少n次;
{n,m}? 匹配至少n次,至多m次; 尽可能少重复;
引擎选项
IgnoreCase 匹配时忽略大小写
Singleline 单行模式
Multiline 多行模式
IgnorePatternWhitespace 忽略表达式中的空白字符,如果需要使用空白字符用转义,#可以用来注释;
练习题
1. 0-999的任意数字;
\d{1-3}\n?
2. ip 地址
# 300.200.10.0 过滤
(\d{1,3}\.){3}(\d{1,3})
# Python包处理 Ip 地址超界
import socket
nw = socket.inet_aton('10.10.10.10')
print(nw, socket.inet_ntoa(nw))
# 文本正则表达式处理Ip超界
(?:(25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:(25[0-5]|2[0-4]\d|[01]?\d\d?))
3. 选择含有ftp的链接,文件名类型为gz或者xz的文件名;
ftp://ftp.xxx.com/pub/file/file-5.4.1.tar.gz
http://ftp.xxx.com/pub/file/file-5.4.1.tar.gz
^(?:ftp).*/((.*?)(gz|xz))
.*ftp.*\.(?:gz|xz)
.*ftp.*/([^/]*\.(?:gz|xz)) # 捕获文件名分组,[^/]决不能出现/
(?<=.*ftp.*/)[^/]*\.(?:gz|xz) # 左边断言判断
Python 的正则表达式
常量
re.MULTILINE | re.DOTALL | re.IGNORECASE
方法
# 编译、提高匹配效率
re.compile(pattern,flags=0)
# 单次匹配match
re.match(battern,string,flags=0) # 未编译
regex.match(string,flags) # 已编译
s = '1234abcd'
regex = re.compile('[ab]')
matcher = regex.match(s,4)
print(matcher)
-----
# 一直匹配search
re.compile(pattern,flags=0)
re.search()
regex.search()
# 全部匹配
# findall() 从左至右
matcher = regex.findall(s)
# finditer() 惰性求值
# 匹配替换
re.sub( )
regex.sub()
reget.subn(replacement ,string,count=0)
replacement 为bytes或者function;
s = "hello tom"
regex = re.compile('t\wm')
print(regex.sub("mageud.com",s,1))
# 分割字符串
re.split(pattern,string,maxsplit=0,flags=0)
s='''01 one
02 two
03 three'''
regex = re.split('[\s\d]+')
# 分组
group(N) 0是返回整个匹配的字符串
group('name') 命名分组
groups 所有的分组
groupdict() 返回所有命名的分组
# 练习
1. 匹配邮箱
changjun@163.com
^\w[\w\.-]*@\w[\w\-\.]*\.[a-z]