Python3.7模块之re

一、特殊字符(这里列出常用的)

参考于:https://docs.python.org/zh-cn/3/library/re.html

符号释义
普通字符匹配自身
.(点) 在默认模式,匹配除了换行的任意字符。如果指定了标签 DOTALL ,它将匹配包括换行符的任意字符。
^(插入符号) 匹配字符串的开头, 并且在 MULTILINE 模式也匹配换行后的首个符号,举例:^表示行的开头, ^\d表示必须以数字开头。$表示行的结束,\d$表示必须以数字结束
$匹配字符串尾或者换行符的前一个字符,在 MULTILINE 模式匹配换行符的前一个字符。 foo 匹配 ‘foo’ 和 ‘foobar’ , 但正则 foo$ 只匹配 ‘foo’。更有趣的是, 在 ‘foo1\nfoo2\n’ 搜索 foo.$ ,通常匹配 ‘foo2’ ,但在 MULTILINE 模式 ,可以匹配到 ‘foo1’ ;在 ‘foo\n’ 搜索 $ 会找到两个空串:一个在换行前,一个在字符串最后。
*对它前面的正则式匹配0到任意次重复, 尽量多的匹配字符串。 ab* 会匹配 ‘a’, ‘ab’, 或者 'a’后面跟随任意个 'b’
+对它前面的正则式匹配1到任意次重复。 ab+ 会匹配 ‘a’ 后面跟随1个以上到任意个 ‘b’,它不会匹配 'a’
?对它前面的正则式匹配0到1次重复。 ab? 会匹配 ‘a’ 或者 'ab’
*?, +?, ??* , + 和 ? 修饰符都是 贪婪的;它们在字符串进行尽可能多的匹配。有时候并不需要这种行为。如果正则式 <.*> 希望找到 ‘<a> b <c>’,它将会匹配整个字符串,而不仅是 ‘<a>’。在修饰符之后添加 ? 将使样式以非贪婪方式或者 :dfn:`最小 方式进行匹配; 尽量 少 的字符将会被匹配。 使用正则式 <.*?> 将会仅仅匹配 <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’
\转义特殊字符(允许你匹配 ‘*’, ‘?’, 或者此类其他),或者表示一个特殊序列;特殊序列之后进行讨论。如果你没有使用原始字符串( r’raw’ )来表达样式,要牢记Python也使用反斜杠作为转义序列;如果转义序列不被Python的分析器识别,反斜杠和字符才能出现在字符串中。如果Python可以识别这个序列,那么反斜杠就应该重复两次。这将导致理解障碍,所以高度推荐,就算是最简单的表达式,也要使用原始字符串
[]用于表示一个字符集合。在一个集合中:字符可以单独列出,比如[amk] 匹配 ‘a’, ‘m’, 或者 ‘k’。可以表示字符范围,通过用 ‘-’ 将两个字符连起来。比如 [a-z] 将匹配任何小写ASCII字符, [0-5][0-9] 将匹配从 00 到 59 的两位数字, [0-9A-Fa-f] 将匹配任何十六进制数位。 如果 - 进行了转义 (比如 [a-z])或者它的位置在首位或者末尾(如 [-a] 或 [a-]),它就只表示普通字符 ‘-’。特殊字符在集合中,失去它的特殊含义。比如 [(+*)] 只会匹配这几个文法字符 ‘(’, ‘+’, ‘*’, or ‘)’。字符类如 \w 或者 \S (如下定义) 在集合内可以接受,它们可以匹配的字符由 ASCII 或者 LOCALE 模式决定。不在集合范围内的字符可以通过 取反 来进行匹配。如果集合首字符是 ‘^’ ,所有 不 在集合内的字符将会被匹配,比如[^5]将匹配所有字符,除了 ‘5’, [^^] 将匹配所有字符,除了 ‘^’. ^ 如果不在集合首位,就没有特殊含义。在集合内要匹配一个字符 ‘]’,有两种方法,要么就在它之前加上反斜杠,要么就把它放到集合首位。比如, [()[]{}] 和 [{}] 都可以匹配括号。Unicode Technical Standard #18 里的嵌套集合和集合操作支持可能在未来添加。这将会改变语法,所以为了帮助这个改变,一个 FutureWarning 将会在有多义的情况里被 raise,包含以下几种情况,集合由 ‘[’ 开始,或者包含下列字符序列 ‘–’, ‘&&’, ‘~~’, 和 ‘||’。为了避免警告,需要将它们用反斜杠转义。
|A|B, A 和 B 可以是任意正则表达式,创建一个正则表达式,匹配 A 或者 B. 任意个正则表达式可以用 ‘|’ 连接。它也可以在组合(见下列)内使用。扫描目标字符串时, ‘|’ 分隔开的正则样式从左到右进行匹配。当一个样式完全匹配时,这个分支就被接受。意思就是,一旦 A 匹配成功, B 就不再进行匹配,即便它能产生一个更好的匹配。或者说,’|’ 操作符绝不贪婪。 如果要匹配 ‘|’ 字符,使用 |, 或者把它包含在字符集里,比如 [|]
(…)(组合),匹配括号内的任意正则表达式,并标识出组合的开始和结尾。匹配完成后,组合的内容可以被获取,并可以在之后用 \number 转义序列进行再次匹配,之后进行详细说明。要匹配字符 ‘(’ 或者 ‘)’, 用 ( 或 ), 或者把它们包含在字符集合里: [(], [)]

由 ‘\’ 和一个字符组成的特殊序列在以下列出。 如果普通字符不是ASCII数位或者ASCII字母,那么正则样式将匹配第二个字符。比如,\$ 匹配字符 ‘$’

符号释义
\number匹配数字代表的组合。每个括号是一个组合,组合从1开始编号。比如 (.+) \1 匹配 ‘the the’ 或者 ‘55 55’, 但不会匹配 ‘thethe’ (注意组合后面的空格)。这个特殊序列只能用于匹配前面99个组合。如果 number 的第一个数位是0, 或者 number 是三个八进制数,它将不会被看作是一个组合,而是八进制的数字值。在 ‘[’ 和 ‘]’ 字符集合内,任何数字转义都被看作是字符
\A只匹配字符串开始
\b匹配空字符串,但只在单词开始或结尾的位置。一个单词被定义为一个单词字符的序列。注意,通常 \b 定义为 \w 和 \W 字符之间,或者 \w 和字符串开始/结尾的边界, 意思就是 r’\bfoo\b’ 匹配 ‘foo’, ‘foo.’, ‘(foo)’, ‘bar foo baz’ 但不匹配 ‘foobar’ 或者 ‘foo3’。默认情况下,Unicode字母和数字是在Unicode样式中使用的,但是可以用 ASCII 标记来更改。如果 LOCALE 标记被设置的话,词的边界是由当前语言区域设置决定的,\b 表示退格字符,以便与Python字符串文本兼容
\B匹配空字符串,但 不 能在词的开头或者结尾。意思就是 r’py\B’ 匹配 ‘python’, ‘py3’, ‘py2’, 但不匹配 ‘py’, ‘py.’, 或者 ‘py!’. \B 是 \b 的取非,所以Unicode样式的词语是由Unicode字母,数字或下划线构成的,虽然可以用 ASCII 标志来改变。如果使用了 LOCALE 标志,则词的边界由当前语言区域设置
\d对于 Unicode (str) 样式:匹配任何Unicode十进制数(就是在Unicode字符目录[Nd]里的字符)。这包括了 [0-9] ,和很多其他的数字字符。如果设置了 ASCII 标志,就只匹配 [0-9] 。对于8位(bytes)样式:匹配任何十进制数,就是 [0-9]
\D匹配任何非十进制数字的字符。就是 \d 取非。 如果设置了 ASCII 标志,就相当于 [^0-9]
\s对于 Unicode (str) 样式:匹配任何Unicode空白字符(包括 [ \t\n\r\f\v] ,还有很多其他字符,比如不同语言排版规则约定的不换行空格)。如果 ASCII 被设置,就只匹配 [ \t\n\r\f\v] 。对于8位(bytes)样式:匹配ASCII中的空白字符,就是 [ \t\n\r\f\v]
\S匹配任何非空白字符。就是 \s 取非。如果设置了 ASCII 标志,就相当于 [^ \t\n\r\f\v]
\w对于 Unicode (str) 样式:匹配Unicode词语的字符,包含了可以构成词语的绝大部分字符,也包括数字和下划线。如果设置了 ASCII 标志,就只匹配 [a-zA-Z0-9_] 。对于8位(bytes)样式:匹配ASCII字符中的数字和字母和下划线,就是 [a-zA-Z0-9_] 。如果设置了 LOCALE 标记,就匹配当前语言区域的数字和字母和下划线
\W匹配任何非词语字符。是 \w 取非。如果设置了 ASCII 标记,就相当于 [^a-zA-Z0-9_] 。如果设置了 LOCALE 标志,就匹配当前语言区域的 非 词语字符
\Z只匹配字符串尾

由于Python的字符串本身也用\转义,因此我们建议使用Python的r前缀,就不用考虑转义的问题了
举例:

s = '123\\abc' # Python的字符串
# 对应的正则表达式字符串变成:
# '123\abc'
改写为r前缀,如下:
s =r'123\abc' # Python的字符串
# # 对应的正则表达式字符串变成:
# # '123\abc'

二、函数语法中flags=0参数——官方解释

re.A
re.ASCII
让 \w, \W, \b, \B, \d, \D, \s 和 \S 只匹配ASCII,而不是Unicode。这只对Unicode样式有效,会被byte样式忽略。相当于前面语法中的内联标志 (?a) 。

注意,为了保持向后兼容, re.U 标记依然存在(还有他的同义 re.UNICODE 和嵌入形式 (?u) ) , 但是这些在 Python 3 是冗余的,因为默认字符串已经是Unicode了(并且Unicode匹配不允许byte出现)。

re.DEBUG
显示编译时的debug信息,没有内联标记。

re.I
re.IGNORECASE
进行忽略大小写匹配;表达式如 [A-Z] 也会匹配小写字符。Unicode匹配(比如 Ü 匹配 ü)同样有用,除非设置了 re.ASCII 标记来禁用非ASCII匹配。当前语言区域不会改变这个标记,除非设置了 re.LOCALE 标记。这个相当于内联标记 (?i) 。

注意,当设置了 IGNORECASE 标记,搜索Unicode样式 [a-z] 或 [A-Z] 的结合时,它将会匹配52个ASCII字符和4个额外的非ASCII字符: ‘İ’ (U+0130, 拉丁大写的 I 带个点在上面), ‘ı’ (U+0131, 拉丁小写没有点的 I ), ‘ſ’ (U+017F, 拉丁小写长 s) and ‘K’ (U+212A, 开尔文符号).如果使用 ASCII 标记,就只匹配 ‘a’ 到 ‘z’ 和 ‘A’ 到 ‘Z’ 。

re.L
re.LOCALE
由当前语言区域决定 \w, \W, \b, \B 和大小写敏感匹配。这个标记只能对byte样式有效。这个标记不推荐使用,因为语言区域机制很不可靠,它一次只能处理一个 "习惯”,而且只对8位字节有效。Unicode匹配在Python 3 里默认启用,并可以处理不同语言。 这个对应内联标记 (?L) 。

在 3.6 版更改: re.LOCALE 只能用于byte样式,而且不能和 re.ASCII 一起用。

在 3.7 版更改: 设置了 re.LOCALE 标记的编译正则对象不再在编译时依赖语言区域设置。语言区域设置只在匹配的时候影响其结果。

re.M
re.MULTILINE
设置以后,样式字符 ‘^’ 匹配字符串的开始,和每一行的开始(换行符后面紧跟的符号);样式字符 ‘$‘匹配字符串尾,和每一行的结尾(换行符前面那个符号)。默认情况下,’^’ 匹配字符串头,’$’ 匹配字符串尾。对应内联标记 (?m) 。

re.S
re.DOTALL
让 ‘.’ 特殊字符匹配任何字符,包括换行符;如果没有这个标记,’.’ 就匹配 除了 换行符的其他任意字符。对应内联标记 (?s) 。

re.X
re.VERBOSE
这个标记允许你编写更具可读性更友好的正则表达式。通过分段和添加注释。空白符号会被忽略,除非在一个字符集合当中或者由反斜杠转义,或者在 *?, (?: or (?P<…> 分组之内。当一个行内有 # 不在字符集和转义序列,那么它之后的所有字符都是注释。

三、re.match

re.match 从字符串的起始位置开始匹配,如果起始位置匹配不成功的话,match()就返回none

语法:re.match(pattern, string, flags=0)

简单的说就是:string(大鱼)里有没有pattern(小鱼)
参数说明:

参数描述
pattern匹配的正则表达式 (pattern就好比小鱼)
string被匹配的字符串(string就好比大鱼)
flags标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等

举例:

import re

print(re.match('韶', '韶风'))   #在起始位置匹配
print(re.match('风', '韶风'))   #不在起始位置匹配

#结果
<re.Match object; span=(0, 1), match='韶'>
None

四、re.search

re.search 扫描整个字符串并返回第一个成功的匹配

语法:re.search(pattern, string, flags=0)

参数说明:

参数描述
pattern匹配的正则表达式 (pattern就好比小鱼)
string被匹配的字符串(string就好比大鱼)
flags标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等

匹配成功re.search方法返回一个匹配的对象,否则返回None

举例:

import re

print(re.search('韶', '韶风'))   #在起始位置匹配
print(re.search('风', '韶风'))   #不在起始位置匹配

#结果
<re.Match object; span=(0, 1), match='韶'>
<re.Match object; span=(1, 2), match='风'>

五、re.match与re.search的区别

re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配,否则返回None

六、re.compile

compile 函数用于编译正则表达式,生成一个正则表达式( Pattern )对象,供 match() 和 search() 这两个函数使用。

语法格式为:

re.compile(pattern[, flags])
prog = re.compile(pattern)
result = prog.match(string)
等价于
result = re.match(pattern, string)

参数:

pattern : 一个字符串形式的正则表达式

flags : 可选,表示匹配模式,比如忽略大小写,多行模式等,具体参数为:
re.I 忽略大小写
re.L 表示特殊字符集 \w, \W, \b, \B, \s, \S 依赖于当前环境
re.M 多行模式
re.S 即为 . 并且包括换行符在内的任意字符(. 不包括换行符)
re.U 表示特殊字符集 \w, \W, \b, \B, \d, \D, \s, \S 依赖于 Unicode 字符属性数据库
re.X 为了增加可读性,忽略空格和 # 后面的注释

举例:

import re

A='123456QWERT!@#$%\n' \
  '<a> a<c>\n' \
  '12s6634566666'
com = re.compile(r'<.*>',re.S)
print(com.search(A).group())
#结果:
<a> a<c>

group([group1, …]) 方法用于获得一个或多个分组匹配的字符串,当要获得整个匹配的子串时,可直接使用 group() 或 group(0); start([group]) 方法用于获取分组匹配的子串在整个字符串中的起始位置(子串第一个字符的索引),参数默认值为0; end([group]) 方法用于获取分组匹配的子串在整个字符串中的结束位置(子串最后一个字符的索引+1),参数默认值为 0; span([group]) 方法返回 (start(group), end(group))

七、findall

在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。
注意: match 和 search 是匹配一次,而findall 是匹配所有

语法:findall(string[, pos[, endpos]])
参数:
string : 待匹配的字符串。
pos : 可选参数,指定字符串的起始位置,默认为 0。
endpos : 可选参数,指定字符串的结束位置,默认为字符串的长度。
import re
A='123456QWERT!@#$%\n' \
  '<a> a<c>\n' \
  '12s6634566666'\

com = re.compile(r'<.*>',re.S)
print(com.findall(A))import re

A='123456QWERT!@#$%\n' \
  '<a> a<c>\n' \
  '12s6634566666'

com = re.findall(r'<.*>',A,re.S)
print(com)

#两种方法的结果:
['<a> a<c>']

八、re.M与re.S对比,还有其中的.*与.*?对比

第一个:
re.M与re.对比

#re.M
import re

A='123456QWERT!@#$%\n' \
  '<a1> a<c>\n' \
  '12s6634566666\n'\
  '<12><2><3>'

com = re.findall(r'<.*>',A,re.M)
print(com)
#结果:
['<a1> a<c>', '<12><2><3>']

#re.S
import re

A = '123456QWERT!@#$%\n' \
  '<a1> a<c>\n' \
  '12s6634566666\n'\
  '<12><2><3>'

com = re.findall(r'<.*>',A,re.S)
print(com)
#结果:
['<a1> a<c>\n12s6634566666\n<12><2><3>']   #这里是贪婪匹配,又因为选择的re.S(可以匹配换行符),所以匹配到了第一个<到最后一个>中的所有内容

#总结:遇到换行的还是使用re.M,如果你需要换行符,就选择re.S

第二个:
.*与.*?对比

#.*
import re

A = '123456QWERT!@#$%\n' \
  '<a1> a<c>\n' \
  '12s6634566666\n'\
  '<12><2><3>'

com = re.findall(r'<.*>',A,re.M)
print(com)
#结果:
['<a1> a<c>', '<12><2><3>']

#.*?
import re

A = '123456QWERT!@#$%\n' \
  '<a1> a<c>\n' \
  '12s6634566666\n'\
  '<12><2><3>'

com = re.findall(r'<.*?>',A,re.M)
print(com)
#结果:
['<a1>', '<c>', '<12>', '<2>', '<3>']

总结:.*是贪婪匹配,就是匹配所有的从第一个<到最后一个>内的所有内容(对它前面的正则式匹配0到任意次重复),尽量多的匹配字符串

简单释义:因为<所以先匹配<,再看.,所以匹配a,再看*,因为后面没有?,所以贪婪匹配,匹配前面的.最大次数,
一直匹配到结尾的>(这个最后的>不在*的匹配里面,因此这个>在A里必须要有,否则匹配不到>,会显示空),匹配就结束,
结果就是['<a1> a<c>', '<12><2><3>']

.*?是非贪婪匹配(*?是一个整体),以最小的方式进行匹配(*?表示对它前面的正则式匹配尽量少的次数,最小0)

简单释义:因为<所以先匹配<,再看.,所以匹配a,再看*,因为后面有?,所以*?是一个整体,使用非贪婪匹配,
匹配前面.的最少的次数,0次,但这里最后有个普通字符>,就把普通字符>前面的全部匹配进去,因而这里的匹配次数最小,
就是匹配离.*?最近的>,所以第一个匹配的就是<a1>,而非['<a1> a<c>', '<12><2><3>'],
接着依次按照匹配<a1>的步骤匹配<c>,<12>,<2>,<3>,最后结果是['<a1>', '<c>', '<12>', '<2>', '<3>'],
这里为什么能匹配这么多,请看前面的findall函数释义哦~
在findall中,只要第一次匹配成功的,就纳入列表,接着匹配下一个,纳入列表的就不再重新匹配

帮助理解.*?的代码

#.*?代码的理解(帮助记忆)
#1.
import re
A = '12>'
com = re.search(r'.*?',A,re.M)
print(com.group())
#结果:
无返回值,什么都没有
#释义:.匹配1,因为*?,所以最小匹配,匹配前面的.0次,所以返回空

#2.
import re
A = '12>'
com = re.search(r'1.*?',A,re.M)
print(com.group())
#结果:
1
#释义:匹配普通字符1,然后.匹配2,因为*?,所以最小匹配,匹配前面的.0次。所以最后返回1

#3.
import re
A = '12>'
com = re.search(r'1.*?>',A,re.M)
print(com.group())
#结果:
12>
#释义:匹配普通字符1,然后匹配2,因为*?,所以最小匹配,但是他结尾还匹配了普通字符>,所以完成尽量少匹配,寻找离*?最近的>(#4就验证了这个道理),之后1到>里面的内容全部匹配

#4.
import re
A = '12><12>'
com = re.search(r'1.*?>',A,re.M)
print(com.group())
#结果:
12>

总结:上面四段代码表示,一般情况下,都是*?按照最小次数匹配,也就是0次,但只要*?后面若有普通字符的匹配,
那就把普通字符前面的全部匹配进去,但后面的普通字符要是最小次数的,匹配.*?后面靠着最近的一个普通字符>,
完成所谓的最小匹配

注:这里的笔记只挑选了几个函数,其他函数语法请参考:https://docs.python.org/zh-cn/3/library/re.html

https://www.runoob.com/python/python-reg-expressions.html

  • 5
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

1stPeak

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值