[TOC] # re库正则表达式的基础使用 > 正则表达式的好处就是可以通过简短表达式精准表达需要匹配内容,然后在文本数据中快速匹配提取到需要的文本内容。 正则表达式可以很简短,也可以很复杂,可能对于同一个结果,不同人写出来的表达式也是千差万别。 为了能够写出优雅的正则表达式,我们首先了解一下它的语法信息,在不断练习实践,才能达到了熟练使用正则表达式的效果。 ## 正则表达式语法 > 为了方便理解记忆,下面将正则表达式进行了归类整理。 ### 元字符含义 | 元字符 | 含义 | | :----- | :-------------------- | | . | (点) 在默认模式,匹配除了换行的任意字符。如果指定了标签 DOTALL ,它将匹配包括换行符的任意字符。 | | \\ | 转义特殊字符(允许你匹配 '*', '?', 或者此类其他),或者表示一个特殊序列; 为了防止`反斜杠灾难`,推荐无论多简单的表达式都要使用 r(raw) 原生字符串来表达,例如: r"\\w.*" | | [] | 用于表示一个字符集合。比如 [amk] 匹配 'a', 'm', 或者 'k'。 可以表示字符范围,通过用 '-' 将两个字符连起来。 比如 [a-z] 将匹配任何小写ASCII字符. 特殊字符在集合中,失去它的特殊含义。比如 [(+*)] 只会匹配这几个文法字符 '(', '+', '*', or ')'。 字符类如 \w 或者 \S (如下定义) 在集合内可以接受,它们可以匹配的字符由 ASCII 或者 LOCALE 模式决定。 '^'字符放在开始位置表示取反操作,例如 [^5] 将匹配所有字符,除了 '5',但是 [5^] 将匹配 '5' 或 '^'。 在集合内要匹配一个字符 ']',有两种方法,要么就在它之前加上反斜杠,要么就把它放到集合首位。比如, [()[\]{}] 和 []()[{}] 都可以匹配括号。 | | \| | A\|B, A 和 B 可以是任意正则表达式,创建一个正则表达式,匹配 A 或者 B. 任意个正则表达式可以用 '\|' 连接。它也可以在组合(见下列)内使用。扫描目标字符串时, '\|' 分隔开的正则样式从左到右进行匹配。当一个样式完全匹配时,这个分支就被接受。意思就是,一旦 A 匹配成功, B 就不再进行匹配,即便它能产生一个更好的匹配。或者说,'\|' 操作符绝不贪婪。 如果要匹配 '\|' 字符,使用 \\\|, 或者把它包含在字符集里,比如 [\|]. | ### 重复匹配 | 元字符 | 含义 | | :---- | :------------- | | * | 对它前面的正则式匹配0到任意次重复, 尽量多的匹配字符串。 ab* 会匹配 'a', 'ab', 或者 'a'``后面跟随任意个 ``'b'。 | | + | 对它前面的正则式匹配1到任意次重复。 ab+ 会匹配 'a' 后面跟随1个以上到任意个 'b',它不会匹配 'a'。 | | ? | 对它前面的正则式匹配0到1次重复。 ab? 会匹配 'a' 或者 'ab'。 | | *?, +?, ?? | **非贪婪模式匹配**,字符串'abc'在使用正则式 <.*?>时 将会仅仅匹配 '<a>'。 | | {m} | 对其之前的正则式指定匹配 m 个重复;少于 m 的话就会导致匹配失败。比如, a{6} 将匹配6个 'a' , 但是不能是5个。 | | {m,n} | 对正则式进行 m 到 n 次匹配,在 m 和 n 之间取尽量多。 比如,a{3,5} 将匹配 3 到 5个 'a'。忽略 m 意为指定下界为0,忽略 n 指定上界为无限次。 比如 a{4,}b 将匹配 'aaaab' 或者1000个 'a' 尾随一个 'b',但不能匹配 'aaab'。逗号不能省略,否则无法辨别修饰符应该忽略哪个边界。 | | {m,n}? | 前一个修饰符的**非贪婪模式**,只匹配尽量少的字符次数。比如,对于 'aaaaaa', a{3,5} 匹配 5个 'a' ,而 a{3,5}? 只匹配3个 'a'。 | ### 边界匹配 | 元字符 | 含义 |模式示例 |匹配成功 | 匹配失败 | | :------ | :------------- |:--------- |:--------- |:-------- | | ^ | 匹配字符串开始,并且在 MULTILINE 模式也匹配换行后的首个符号。 | ^ABC | ABC | abcABC | | $ | 匹配字符串末尾,在 MULTILINE 模式匹配换行符的前一个字符。 | ABC\$ | abcABC | abcdABCD| | \A | 只匹配字符串开始。 | ^ABC | ABC | abcABC | | \Z | 只匹配字符串末尾。 | ABC$ | xABC | xABCD| | \b | 单词边界匹配,匹配空字符串,但只在单词开始或结尾的位置。 | r\bfoo\b | 'foo','foo.' | 'abcfooxyz', 'foo3' | | \B | 匹配空字符串,但不能在词的开头或者结尾。 与\b语义相反。 | r'py\B' | 'python','py3' | 'py','py.' | | \d | Unicode下匹配数字0-9和其他数字符号,ASCII下匹配0-9的数字。 | r'A\dC' | 'A2C' | 'ABC' | | \D | 匹配任何非十进制数字的字符。就是 \d 取非。 | r'A\DC' | 'ABC' | 'A2C' | | \s | 匹配ASCII中的空白字符,就是 [ \t\n\r\f\v] | r'bob\sis' | 'bob is ...' | 'bobisaboy' | | \S | 匹配任何非空白字符。就是 \s 取非。如果设置了 ASCII 标志,就相当于 [^ \t\n\r\f\v] 。 | r'(\S+)\s+(\S+)' | 'hello world' | 'helloworld' | | \w | 匹配Unicode词语的字符,包含了可以构成词语的绝大部分字符,也包括数字和下划线。如果设置了 ASCII 标志,就只匹配 [a-zA-Z0-9_] 。 匹配ASCII字符中的数字和字母和下划线,就是 [a-zA-Z0-9_] 。如果设置了 LOCALE 标记,就匹配当前语言区域的数字和字母和下划线。 | r'\b\w+\b' | 'adkfa' | '[]' ,'&' | | \W | 匹配非单词字符的字符。这与 \w 正相反。如果使用了 ASCII 旗标,这就等价于 [^a-zA-Z0-9_]。如果使用了 LOCALE 旗标,则会匹配当前区域中既非字母数字也非下划线的字符。 | r'name\Wvalue' | 'name=value' | 'name_value'| ### 分组 | 元字符 | 含义 |模式示例 |匹配成功 | 匹配失败 | | :------ | :------------- |:--------- |:--------- |:-------- | | (...) | (组合),匹配括号内的任意正则表达式,并标识出组合的开始和结尾。匹配完成后,组合的内容可以被获取,并可以在之后用 \\number 转义序列进行再次匹配,之后进行详细说明。要匹配字符 '(' 或者 ')', 用 \\( 或 \\), 或者把它们包含在字符集合里: [(], [)]. | r'1(abc\|xyz)2' | '1abc2','1xyz2' | '1abcxyz2' | |(?P\<name\>) | (命名组合)类似正则组合,但是匹配到的子串组在外部是通过定义的 name 来获取的。 | (?P\<quote>['"]).*?(?P=quote) |"xyz"|abc(无引号)| | (?P=name) | 引用别名为name的分组字符串 |(?P\<quote>['"]).*?(?P=quote) |"xyz"|abc(无引号)| | \\number | 引用编号为<number>的分组字符串 | (['"]).*?\1 |"xyz"|abc(无引号)| ### 特殊组合(使用()表达式但是却不作为分组获取) | 元字符 | 含义 |模式示例 |匹配成功 | 匹配失败 | | :------ | :------------- |:--------- |:--------- |:-------- | |(?:…) |正则括号的非捕获版本。 匹配在括号内的任何正则表达式,但该分组所匹配的子字符串 不能 在执行匹配后被`获取`或是之后在模式中被`引用`。这是与(...) 分组之间的区别。例如这样使用是错误的r'(?:abc)\\1'| r'(?i)(http://.*?(?:jpg|png|jpeg))'| 'http:xxx.xxx/1001.jpg' | 'http:xxx.xxx/1002.svg' | | (?aiLmsux)|( 'a', 'i', 'L', 'm', 's', 'u', 'x' 中的一个或多个) 这个组合匹配一个空字符串;这些字符对正则表达式设置以下标记 re.A (只匹配ASCII字符), re.I (忽略大小写), re.L (语言依赖), re.M (多行模式), re.S (点dot匹配全部字符), re.U (Unicode匹配), and re.X (冗长模式)。 (这些标记在 模块内容 中描述) 如果你想将这些标记包含在正则表达式中,这个方法就很有用,免去了在 re.compile() 中传递 flag 参数。标记应该在表达式字符串首位表示。 |r'(?i)abc' |Abc | axbc | |(?#…) | 注释;里面的内容会被忽略。| name(?#this is a comment)=123 | name=123 | namexxxx | |(?=…) |匹配 … 的内容,但是并不消费样式的内容。这个叫做 lookahead assertion。 | Isaac (?=Asimov)|IsaacAsimov | Isaac| |(?!…) |匹配 … 不符合的情况。这个叫 negative lookahead assertion (前视取反)。 | Isaac (?!Asimov)| Isaac| IsaacAsimov| |(?\<=…) |匹配字符串的当前位置,它的前面匹配 … 的内容到当前位置。这叫:dfn:positive lookbehind assertion (正向后视断定)。**注意以 positive lookbehind assertions 开始的样式,如 (?<=abc)def ,并不是从 a 开始搜索,而是从 d 往回看的。你可能更加愿意使用 search() 函数,而不是 match() 函数**,使用match()函数会出现匹配失败的情况的。 |r'(?<=-)\w+' |abc-def | xyzdef | |(?<!…) | 匹配当前位置之前不是 ... 的样式。这个叫 negative lookbehind assertion (后视断定取非)。|r'(?<!-)\w+' | xyzdef | abc-def| ## 正则函数使用 | 函数定义 | 含义 | | :------ | :------------- | |re.search(pattern, string, flags=0) | 扫描整个 字符串 找到匹配样式的第一个位置,并返回一个相应的 匹配对象。如果没有匹配,就返回一个 None ; 注意这和找到一个零长度匹配是不同的。| |re.match(pattern, string, flags=0)|如果 string 开始的0或者多个字符匹配到了正则表达式样式,就返回一个相应的 匹配对象 。 如果没有匹配,就返回 None ;注意它跟零长度匹配是不同的。注意即便是 MULTILINE 多行模式, re.match() 也只匹配字符串的开始位置,而不匹配每行开始。如果你想定位 string 的任何位置,使用 search() 来替代。| |re.fullmatch(pattern, string, flags=0)|如果整个 string 匹配到正则表达式样式,就返回一个相应的 匹配对象 。 否则就返回一个 None ;注意这跟零长度匹配是不同的。| |re.split(pattern, string, maxsplit=0, flags=0)|用 pattern 分开 string 。 如果在 pattern 中捕获到括号,那么所有的组里的文字也会包含在列表里。如果 maxsplit 非零, 最多进行 maxsplit 次分隔, 剩下的字符全部返回到列表的最后一个元素。| |re.findall(pattern, string, flags=0)|对 string 返回一个不重复的 pattern 的匹配列表, string 从左到右进行扫描,匹配按找到的顺序返回。如果样式里存在一到多个组,就返回一个组合列表;就是一个元组的列表(如果样式里有超过一个组合的话)。空匹配也会包含在结果里。| |re.finditer(pattern, string, flags=0)|pattern 在 string 里所有的非重复匹配,返回为一个迭代器 iterator 保存了 匹配对象 。 string 从左到右扫描,匹配按顺序排列。空匹配也包含在结果里。| |re.sub(pattern, repl, string, count=0, flags=0) | 返回通过使用 repl 替换在 string 最左边非重叠出现的 pattern 而获得的字符串。 如果样式没有找到,则不加改变地返回 string。 repl 可以是字符串或函数;如为字符串,则其中任何反斜杠转义序列都会被处理。| |re.subn(pattern, repl, string, count=0, flags=0) | 行为与 sub() 相同,但是返回一个元组 (字符串, 替换次数).| |re.escape(pattern) |转义 pattern 中的特殊字符。如果你想对任意可能包含正则表达式元字符的文本字符串进行匹配,它就是有用的。 | |re.purge() | 清除正则表达式的缓存。| ### match() 与 search() 函数比较 Python 提供了两种不同的操作:基于 re.match() 检查字符串开头,或者 re.search() 检查字符串的任意位置(默认Perl中的行为)。 例如: ```Python >>> >>> re.match("c", "abcdef") # No match >>> re.search("c", "abcdef") # Match <re.Match object; span=(2, 3), match='c'> ``` 在 search() 中,可以用 '^' 作为开始来限制匹配到字符串的首位: ```Python >>> >>> re.match("c", "abcdef") # No match >>> re.search("^c", "abcdef") # No match >>> re.search("^a", "abcdef") # Match <re.Match object; span=(0, 1), match='a'> ``` **注意** `MULTILINE` 多行模式中函数 match() 只匹配字符串的开始,但使用 search() 和以 '^' 开始的正则表达式会匹配每行的开始 ```Python >>> >>> re.match('X', 'A\nB\nX', re.MULTILINE) # No match >>> re.search('^X', 'A\nB\nX', re.MULTILINE) # Match <re.Match object; span=(4, 5), match='X'> ``` ## 匹配对象处理函数 | 函数定义 | 含义 | | :-------- | :------------- | | Match.expand(template) | 对 template 进行反斜杠转义替换并且返回,就像 sub() 方法中一样。转义如同 \n 被转换成合适的字符,数字引用(\1, \2)和命名组合(\g<1>, \g<name>) 替换为相应组合的内容。| |Match.group([group1, ...])|返回一个或者多个匹配的子组。如果只有一个参数,结果就是一个字符串,如果有多个参数,结果就是一个元组(每个参数对应一个项),如果没有参数,组1默认到0(整个匹配都被返回)。| |Match.groups(default=None)|返回一个元组,包含所有匹配的子组,在样式中出现的从1到任意多的组合。 default 参数用于不参与匹配的情况,默认为 None。| ```Python >>> m = re.match(r"(\w+) (\w+)", "Isaac Newton, physicist") >>> m.group(0) # The entire match 'Isaac Newton' >>> m.group(1) # The first parenthesized subgroup. 'Isaac' >>> m.group(2) # The second parenthesized subgroup. 'Newton' >>> m.group(1, 2) # Multiple arguments give us a tuple. ('Isaac', 'Newton') >>> m = re.match(r"(\d+)\.?(\d+)?", "24") >>> m.groups() # Second group defaults to None. ('24', None) >>> m.groups('0') # Now, the second group defaults to '0'. ('24', '0') ```