操作
compile
- compile 常用的表达式更高效:使用编译的表达式能避免高速缓存查找开销,将编译工作转移到应用程序启动时,而不是程序响应用户操作
- 在字符串前加个
r反斜杠就不会被任何特殊方式处理 re.findall(rf'{t}', s):f表示t可以使用变量re.compile(pattern, re.IGNORECASE): IGNORECASE 忽略大小写re.compile(pattern, re.MULTILINE): 是否按行匹配,带参数按行,不带参数整个字符串为整体(不考虑换行符)re.compile(pattern, re.DOTALL): 默认不匹配换行符,带参数匹配换行符re.compile(pattern, re.Unicode | re.VERBOSE): 让 pattern 看起来更易读。多个标志可以通过按位 OR-ing 它们来指定。如re.I | re.M被设置成 I 和 M 标志- 嵌入标志(编译表达式无法添加标志时,可以在表达式字符串本身内嵌入标志)
- 打开不区分大小写匹配项:
(?i)添加到 pattern 的最前面就好 i: IGNORECASE; m: MULTILINE; s: DOTALL; u: UNICODE; x: VERBOSE
- 打开不区分大小写匹配项:
无捕获组和命名组
(?:pattern): 无捕获组,对于修改已有组尤其有用,因为你可以不用改变所有其他组号的情况下添加一个新组。(?P<name>...)定义一个命名组,(?P=name)则是对命名组的逆向引用;逆向引用允许你指定先前捕获组的内容,该组也必须在字符串当前位置被找到。举个例子,如果组 1 的内容能够在当前位置找到的话,\1就成功否则失败。除了用数字指定组,它可以用名字来指定,如:(\b\w+)\s+\1也可以被写成(?P<word>\b\w+)\s+(?P=word)re.compile(r'(\w+)\1\1\1'): 匹配一个字重复四次的那个「字」re.compile(r'((\w+)\2+)'): 匹配重复两次或两次以上的,返回对应的值和那个重复的「字」,必须整个用括号括起来
条件表达式
条件:(?(id)yes-expression|no-expression), id 是 group name or number
yes-expressionis the pattern to use if the group has a value,如果 group 有返回值时执行no-expressionis the pattern to use otherwise.(?=(<.*>$)|([^<].*[^>]$))条件表达式例子1:(?(name)(?=(\w+))|(?=([^<].*[^>]$))),如果找到name,执行前面的,否则执行后面的条件表达式例子2:(?(name)(?P<brackets>(?=(<.*>$)))|(?=([^<].*[^>]$)))调用(非条件表达式):(?P<email>(?P=first_name)\.(?P=last_name)@([\w\d.]+\.)+(com|org|edu))
环视
(?!pattern): 前向否定,不匹配 pattern,匹配不是 bat 或 exe 后缀的:.*[.](?!bat$|exe$).*$;re.compile(r'Isaac(?!Asimov)'):Isaac 前面有 Asimov 不能匹配 Isaac(?=pattern): 前向肯定,匹配,A positive look ahead assertion,条件不占匹配符;re.compile(r'Isaac(?=Asimov)'):Isaac 前面有 Asimov 才能匹配 Isaac(?<!noreply)后向否定,放在匹配到的 username 下和(?!noreply@.*$)放在最前面匹配是一样的;re.compile(r'(?<!Asimov)Isaac'):Isaac 后面有 Asimov 不能匹配 Isaac(?<=@): 后向肯定,A positive look behind assertion, must use a fixed length pattern;re.compile(r'(?<=Asimov)Isaac'):Isaac 后面有 Asimov 才能匹配 Isaac
上面的只支持固定长度,如果要使用可变长度,需要 regex 包:mrabarnett / mrab-regex — Bitbucket
regex.compile(rf'(?<![{quantifier}]+\w*)(之一)([{punc}]?)'): 非固定宽度否定逆序环视,用后面的符号即做隔断,在结尾又可不存在。不等于 “数量词” + XXX + 之一,且标点结尾的;注意:quantifier 是变量regex的环视可以跳跃查找,而普通的re只能连在一起。举个例子:找到 非量词 + 之一- 普通正则:
(!量词)\w+之一:这样因为\w包括了量词,所以并不能查找出来 - 环视方法:
(?<!量词)\w+之一:可以分成三部分:非量词+其他词+之一
- 普通正则:
- 再几个例子:
regex.match(r'(?(?=\d)\d+|\w+)', '123abc')匹配到 123regex.match(r'(?(?=\d)\d+|\w+)', 'abc123')匹配到 abc123,只能匹配第二个regex.match(r'(?:(?=\d)\d+\b|\w+)', '123a')匹配到 123a,匹配第二个regex.match(r'(?(?=\d)\d+\b|\w+)', '123a')结果为 None,第一个如果匹配到就不会再到第二个regex.match(r'(?(?=\d)\d+\b|\w+)', 'abc')匹配到 abc,匹配第二个regex.match(r'(?(?=\d)\d+\b|\w+)', '123')匹配到 123,匹配第一个
匹配查找
re.search()- 使用 pattern 扫描文本
- 如果找到则返回 Match 对象,否则返回
None,match.start(), match.end()或match.span()返回匹配到对象的起止位置 pattern.search():返回子串,而不是re.search()的整个字符串
re.match()- 只有 pattern 在文本的最开始才返回结果,否则返回
None
- 只有 pattern 在文本的最开始才返回结果,否则返回
re.findall()finditer返回一个迭代器,可以使用match.start(), match.end()返回起止位置re.findall(r'a((a*)(b*))',t): 类似这种,第一个 a 是不返回到结果的,只返回括号里面的
- 如果没有匹配到的话,
match()和search()将返回None。如果成功的话,就会返回一个MatchObject实例,其中有这次匹配的信息:它是从哪里开始和结束,它所匹配的子串等等。findall()在它返回结果时不得不创建一个列表。 groups()- 返回匹配到的字符序列,不需要再用起止位置确定返回的字符串
group(index): 返回单独的一个 group(匹配到的结果)match.groupdict()返回{名字:值}的字典- 组可以被嵌套。计数的数值可以通过从左到右计算打开的括号数来确定。
The groups()方法返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。
- list 作为参数:
re.compile('二' + str(["位", "十", "百", "千", "万", "亿"]))- 和 list 的顺序有关,所以首字一样的,长的放前面,否则长的匹配不到(肯定模式)
- 会匹配到空格(list 元素中间有空格)
- 还会匹配到单个词里面的每个词中间字的组合(肯定模式)。
- 不推荐这样的写法。
分割替换
split(string [, maxsplit = 0])p2 = re.compile(r'(\W+)'): 打印出定界符,如果不需要则为:p = re.compile(r'\W+')re.compile().split(text, num): num 非 0 时,最多分成 num 段
sub(replacement, string[, count = 0])- 可选参数 count 是模式匹配后替换的最大次数;count 必须是非负整数。缺省值是 0 表示替换所有的匹配。
- 空匹配只有在它们没有紧挨着前一个匹配时才会被替换掉。
re.compile('x*').sub('-', 'abxd'):'-a-b-d-' - 可以指定用
(?P<name>...)语法定义的命名组。“\g<name>” 将通过组名 “name” 用子串来匹配,并且 “\g<number>” 使用相应的组号。使用它可以消除组号和周围文字数字之间的任何歧义。 - 替换也可以是一个函数,该函数将会被模式中每一个不重复的匹配所调用。
subn()返回修改后的字符串和替换的数量
replace: 更快的替换translate(): 从一个字符串中删除单个字符或用另一个字符来替代它- 可以用
re.sub('\n',' ', s)这样来实现,但translate()能够实现这两个任务,而且比任何正则表达式操作起来更快。 translate需要配合string.maketrans使用。例如:import string后'a1b3'.translate(string.maketrans('ab', 'cd'))
要义
数量
{}多少次*等于{0,},0 次或任意正次数+等于{1,},1 次或任意正次数?等于{0,1},0 次或 1 次- pattern 后面加「?」(英文的问号)就是非贪婪匹配,默认是贪婪匹配(匹配尽可能多的字符)。也就是匹配数量少的次数(也就是 {} 左边的数字次数)
转义
- 范围
[ab]: a or b,[\w\d.+-]里面的「.±」就是代表自身a[ab]+: aa… or ab…a[ab]+?: aa or ab[^-. ]+: 不含-, ., 空格的,用补集来匹配不在区间范围内的字符,其做法是把^作为类别的首个字符;其它地方的^只会简单匹配^字符本身[A-Z][a-z]+: 一个大写字母后面跟着小写字母- 元字符在类别里(
[]里)并不起作用 \p{L}+匹配任意的 letter,比如 abc\p{N}+匹配任意的 number,比如 123
- 小数点
.表示任何单独的字符,除了换行符(\n)a.*b: a 后面任意字符,b 结尾a.*?b: a 后面任意字符,b 结尾,非贪婪
- 反斜杠
\d: a digit\D: a non-digit\s: whitespace(tab, space, newline, etc.)\S: non-whitespace\w: alphanumeric 字母数字\W: non-alphanumeric 非字母数字(标点,符号如#等)\: 转义
- 大多数字母和字符一般都会和自身匹配
位置
^: string or line 开始$: string or line 结尾\A: string 开始\Z: string 结尾\b: empty string at the beginning or end of a word\B: empty string not at the beginning or end of a word- 例子
r'^\w+', # word at start of stringr'\A\w+', # word at start of stringr'\w+\S*$', # word at end of string, with optional punctuationr'\w+\S*\Z', # word at end of string, with optional punctuationr'\w*t\w*', # word containing 't'r'\bt\w+', # 't' at start of wordr'\w+t\b', # 't' at end of wordr'\Bt\B', # 't', not start or end of word
逻辑
(): 分组,视为整体|: 管道符,要么用左边的字符串匹配,要么用右边的匹配
例子
1 | p_email = re.compile(''' |
参考
- 6.2. re — Regular expression operations — Python 3.6.2 documentation
- Python Module of the Week上的讲 Python 的 re 包 https://pymotw.com/2/re/,可参考[笔记](https://nbviewer.jupyter.org/github/hscspring/All4NLP/blob/master/Re/Python-Re-Pymotw.ipynb)
- Ubuntu Wiki上的 Python正则表达式操作指南 - Ubuntu中文,可参考笔记
- 关于 Regex 的笔记
- Regular-Expressions.info - Regex Tutorial, Examples and Reference - Regexp Patterns
高阶
-
Regex 工具
- regexper 可视化:https://regexper.com/
- pythex 在线测试正则表达式 http://pythex.org/
- regex101 另一个很漂亮的在线正则表达式测试器 https://regex101.com/
-
进阶阅读
- re2 一个更快的Cython实现 https://pypi.python.org/pypi/re2/
- pyahocorasick 用字典树和Aho-Corasick自动机实现的超快的正则引擎 https://pypi.python.org/pypi/pyahocorasick/
- PythonVerbalExpressions 类自然语言构造正则表达式 https://github.com/VerbalExpressions/PythonVerbalExpressions
- Exrex 从正则表达式生成随机字符串 https://github.com/asciimoo/exrex
- PyParsing 构造正则语法(和更多规则)和提取的引擎 http://pyparsing.wikispaces.com/
- Parsley 更人性化的正则表达语法 http://parsley.readthedocs.io/en/latest/tutorial.html