参考:python文档https://docs.python.org/zh-cn/3/library/re.html#module-contents
目录
1.整体了解
2. 语法
3. re.match
4. re.search
re.match与re.search的区别
5. 检索和替换
repl 参数是一个函数
6. re.compile 函数
7. findall
8. re.finditer
9. re.split
10. 正则表达式对象
re.RegexObject
re.MatchObject
11. 正则表达式修饰符 - 可选标志
12. 正则表达式实例
正则表达式:一套规则,可以在字符串文本中进行搜查替换等
正则使用步骤:
正则的常用方法:
贪婪与非贪婪模式
点-星匹配所有字符:
>>> nongreedyRegex = re.compile(r'<.*?>')
>>> mo = nongreedyRegex.search(' for dinner.>')
>>> mo.group()
''
>>> greedyRegex = re.compile(r'<.*>')
>>> mo = greedyRegex.search(' for dinner.>')
>>> mo.group()
' for dinner.>'
python里面数量词默认是贪婪模式
例如:
查找文本abbbbbbbccc
re结果是: ab*
贪婪模式结果是:abbbbbbb
非贪婪模式结果是:a
模式字符串使用特殊的语法来表示一个正则表达式:
'A'
、 'a'
或者 '0'
,都是最简单的正则表达式,它们就匹配自身。你可以拼接普通字符,所以 last
匹配字符串 'last'
. *
, +
, ?
, {m,n}
, 等) 不能直接嵌套。这样避免了非贪婪后缀 ?
修饰符,和其他实现中的修饰符产生的多义性。要应用一个内层重复嵌套,可以使用括号。 比如,表达式 (?:a{6})*
匹配6个 'a'
字符重复任意次数。由于正则表达式通常都包含反斜杠,所以你最好使用原始字符串来表示它们。模式元素(如 r'\t',等价于 '\\t')匹配相应的特殊字符。
下表列出了正则表达式模式语法中的特殊元素。如果你使用模式的同时提供了可选的标志参数,某些模式元素的含义会改变。
模式 | 描述 |
---|---|
^ | 匹配字符串的开头。 当^表示取反的时候,只有一种情况,就是在中括号里面,而且是每一个字符之外的 |
$ | 匹配字符串的末尾。 |
. | 匹配任意字符,除了换行符,当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符。 只匹配一个字符 |
[...] | 用来表示一组字符,单独列出:[amk] 匹配 'a','m'或'k' |
[^...] | 不在[]中的字符:[^abc] 匹配除了a,b,c之外的字符。 |
re* | 匹配0个或多个的表达式。 |
re+ | 匹配1个或多个的表达式。 |
re? | 匹配0个或1个由前面的正则表达式定义的片段,非贪婪方式 问号在正则表达式中可能有两种含义: 声明非贪心匹配或表示可选的分组。 |
re{n} | 精确匹配 n 个前面表达式。例如, o{2} 不能匹配 "Bob" 中的 "o",但是能匹配 "food" 中的两个 o。 |
re{n,} | 匹配 n 个前面表达式。例如, o{2,} 不能匹配"Bob"中的"o",但能匹配 "foooood"中的所有 o。 "o{1,}" 等价于 "o+"; "o{0,}" 则等价于 "o*"。 |
re{n, m} | 匹配 n 到 m 次由前面的正则表达式定义的片段,贪婪方式,逗号和m之间不能有空格;
前一个修饰符的非贪婪模式,只匹配尽量少的字符次数。比如,对于 |
a| b | 匹配a或b |
(re) | 对正则表达式分组并记住匹配的文本 |
(?imx) | 正则表达式包含三种可选标志:i, m, 或 x 。只影响括号中的区域。 eg:re.search(r'(?i)[a-z]+', 'Axad') |
(?-imx) 错误 | 正则表达式关闭 i, m, 或 x 可选标志。只影响括号中的区域。 官方文档没有此功能 |
(?: re) | 类似 (...),但是不表示一个组。 正则括号的非捕获版本。 匹配在括号内的任何正则表达式,但该分组所匹配的子字符串 不能 在执行匹配后被获取或是之后在模式中被引用。 匹配“first”,且其前面是”a“的情况: eg:result = re.search(r'(?:a)first', 'afirst bfirst').group() :result = afirst |
区别 (?i)与(?i:re) |
(?!):其后面的内容不区分大小写; (?!:re):用re去匹配内容,且其后面的内容不区分大小写 |
(?imx: re) | 在括号中使用i, m, 或 x 可选标志 eg:匹配first之前是a的句子,不区分大小写 re.search(r'(?i:a)first', 'Afirst bfirst'): |
(?-imx: re) | 在括号中不使用i, m, 或 x 可选标志 eg:匹配first之前是a的句子,区分大小写 re.search(r'(?-i:a)first', 'Afirst bfirst') :None |
(?#...) | 注释. |
(?P |
(命名组合)类似正则组合,但是匹配到的子串组在外部是通过定义的 name 来获取的。组合名必须是有效的Python标识符,并且每个组合名只能用一个正则表达式定义,只能定义一次。一个符号组合同样是一个数字组合,就像这个组合没有被命名一样。 eg: a.group('num') = 2000万 a.group(1) = 生猪 a.group(2) = 2000万 a.group(3) = 只 |
(?P=name) | 反向引用一个命名组合;它匹配前面那个叫 name 的命名组中匹配到的串同样的字串。 eg: a = re.search('(?P a.group(1) = 生猪 a.group(2) = 2000万 a.group(3) = 只 |
(?= re) | 前向肯定界定符。如果所含正则表达式,以 ... 表示,在当前位置成功匹配时成功,否则失败。但一旦所含表达式已经尝试,匹配引擎根本没有提高;模式的剩余部分还要尝试界定符的右边。比如, Isaac (?=Asimov) 匹配 'Isaac ' 只有在后面是 'Asimov' 的时候。 |
(?! re) | 前向否定界定符。与肯定界定符相反;当所含表达式不能在字符串当前位置匹配时成功。比如说, Isaac (?!Asimov) 只有后面 不 是 'Asimov' 的时候才匹配 'Isaac ' 。 |
(?>=re) | 正向后视断定,匹配的独立模式,省去回溯。如 m = re.search('(?<=abc)def', 'gcdabcdef') m.group(0) # 'def' m = re.search(r'(?<=-)\w+', 'spam--egg') m.group(0) # 'egg' |
(? | 后视断定取非:类似正向后视断定,包含的样式匹配必须是定长的。 注意:
|
\w | 匹配字母数字及下划线,等价于'[A-Za-z0-9_]'。 |
\W | 匹配非字母数字及下划线 |
\s | 匹配任意空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。 |
\S | 匹配任意非空字符 |
\d | 匹配任意数字,等价于 [0-9]. |
\D | 匹配任意非数字 |
\A | 匹配字符串开始 |
\Z | 匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串。 |
\z | 匹配字符串结束 |
\G | 匹配最后匹配完成的位置。 |
\b | 匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。 |
\B | 匹配非单词边界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。 |
\n, \t, 等. | 匹配一个换行符,匹配一个制表符等 |
\1...\9 | 匹配第n个分组的内容。 |
\10 | 匹配第n个分组的内容,如果它经匹配。否则指的是八进制字符码的表达式。 |
命名组合可以在三种上下文中引用。如果样式是 (?P
(也就是说,匹配单引号或者双引号括起来的字符串):['"]).*?(?P=quote)
引用组合 "quote" 的上下文 |
引用方法 |
---|---|
在正则式自身内 |
|
处理匹配对象 m |
|
传递到 |
|
(?(id/name)yes-pattern|no-pattern) | 如果给定的 id 或 name 存在,将会尝试匹配 (?(1)>|$):表示匹配的第1组若存在,将匹配>,不存在将匹配$。 |
\number | 匹配数字代表的组合。每个括号是一个组合,组合从1开始编号。比如 (.+) \1 匹配 'the the' 或者 '55 55' , 但不会匹配 'thethe' (注意组合后面的空格)。这个特殊序列只能用于匹配前面99个组合。如果 number 的第一个数位是0, 或者 number 是三个八进制数,它将不会被看作是一个组合,而是八进制的数字值。在 '[' 和 ']' 字符集合内,任何数字转义都被看作是字符。 |
|
m = re.search(r'(<)?(\w+@\w+(?:\.\w+)+)(?(1)>|$)','[email protected]')
m.group(0) # '[email protected]'
m = re.search(r'(<)?(\w+@\w+(?:\.\w+)+)(?(1)>|$)','')
m.group(0) # ''
re.match 尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none。
函数语法:re.match(pattern, string, flags=0)
re.match()返回的是一个
方法名称 | 作用 |
---|---|
group | 以str形式返回对象中match的元素 |
start | 返回开始位置 |
end | 返回结束位置 |
span | 以tuple形式返回范围,包含开头,不包含结尾 |
当匹配成功时返回一个 Match 对象,其中:
group([group1, …])
方法用于获得一个或多个分组匹配的字符串,当要获得整个匹配的子串时,可直接使用 group()
或 group(0)
;start([group])
方法用于获取分组匹配的子串在整个字符串中的起始位置(子串第一个字符的索引),参数默认值为 0;end([group])
方法用于获取分组匹配的子串在整个字符串中的结束位置(子串最后一个字符的索引+1),参数默认值为 0;span([group])
方法返回 (start(group), end(group))
。组()的例子及区别:
*?
, +?
, ??
'*'
, '+'
,和 '?'
修饰符都是 贪婪的;它们在字符串进行尽可能多的匹配。有时候并不需要这种行为。如果正则式 <.*>
希望找到 ' b
,它将会匹配整个字符串,而不仅是 ''
。在修饰符之后添加 ?
将使样式以 非贪婪`方式或者 :dfn:`最小 方式进行匹配; 尽量 少 的字符将会被匹配。 使用正则式 <.*?>
将会仅仅匹配 ''
。
解析:
首先,这是一个字符串,前面的一个 r 表示字符串为非转义的原始字符串,让编译器忽略反斜杠,也就是忽略转义字符。但是这个字符串里没有反斜杠,所以这个 r 可有可无。
matchObj.group() 等同于 matchObj.group(0),表示匹配到的完整文本字符
matchObj.group(1) 得到第一组匹配结果,也就是(.*)匹配到的
matchObj.group(2) 得到第二组匹配结果,也就是(.*?)匹配到的
因为只有匹配结果中只有两组,所以如果填 3 时会报错。
匹配对象方法 | 描述 |
---|---|
group(num=0) | 匹配的整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。 |
groups() | 返回一个包含所有小组字符串的元组,即多个值的元组tuple, 所以你可以使用多重复制的技巧, 每个值赋给一个独立的变量。 >>> mo.groups() # ('415', '555-4242') |
re.search() 扫描整个字符串。
返回:一个Match对象,包含第一个成功匹配的文本。
函数语法:re.search(pattern, string, flags=0)
import re
print(re.search('www', 'www.runoob.com').span()) # 在起始位置匹配
print(re.search('com', 'www.runoob.com').span()) # 不在起始位置匹配
(0, 3)
(11, 14)
#!/usr/bin/python
import re
line = "Cats are smarter than dogs";
searchObj = re.search( r'(.*) are (.*?) .*', line, re.M|re.I)
if searchObj:
print "searchObj.group() : ", searchObj.group()
print "searchObj.group(1) : ", searchObj.group(1)
print "searchObj.group(2) : ", searchObj.group(2)
else:
print "Nothing found!!"
searchObj.group() : Cats are smarter than dogs
searchObj.group(1) : Cats
searchObj.group(2) : smarter
re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配。
(1)Python 的 re 模块提供了re.sub用于替换字符串中的匹配项
语法:re.sub(pattern, repl, string, count=0, flags=0) 将string中检索到的pattern替换为repl
参数:
import re
phone = "2004-959-559 # 这是一个国外电话号码"
# 删除字符串中的 Python注释
num = re.sub(r'#.*$', "", phone) # 将num中的 #.*$ 替换为空
print("电话号码是: ", num)
# 删除非数字(-)的字符串
num = re.sub(r'\D', "", phone)
print("电话号码是 : ", num)
电话号码是: 2004-959-559
电话号码是 : 2004959559
(2)Regex对象的 sub()方法:
语法:regex.sub(repl,string)
需要传入两个参数。第一个参数是一个字符串, 用于取代发现的匹配。第二个参数是一个字符串,即正则表达式。 sub()方法返回替换完成后的字符串。例如, 在交互式环境中输入以下代码:
>>> namesRegex = re.compile(r'Agent \w+')
>>> namesRegex.sub('CENSORED', 'Agent Alice gave the secret documents to Agent Bob.')
'CENSORED gave the secret documents to CENSORED.
有时候,你可能需要使用匹配的文本本身,作为替换的一部分。在 sub()的第一个参数中,可以输入\1、 \2、 \3……表示“在替换中输入分组 1、 2、 3……的文本”。例如,假定想要隐去密探的姓名,只显示他们姓名的第一个字母。要做到这一点,可以使用正则表达式 Agent (\w)\w*,传入 r'\1****'作为 sub()的第一个参数。字符串中的\1 将由分组 1 匹配的文本所替代,也就是正则表达式的(\w)分组:
import re
agentRegex = re.compile(r'Agent (\w)\w*')
agentRegex.sub(r'\1****', 'Agent Alice told Agent Carol that Agent Eve knew Agent Bob was a double agent.')
结果为:A**** told C**** that E**** knew B**** was a double agent.'
以下实例中将字符串中的匹配的数字乘以 2:
import re
def double(m):
print(m)
value = int(m.group('value'))
return str(value * 2)
s = 'A23G4HFD567'
result = re.sub('(?P\d+)', double, s)
print(result)
A46G8HFD1134
compile 函数用于编译正则表达式,生成一个正则表达式( Pattern )对象,供 match() 和 search() 这两个函数使用。
语法格式为:re.compile(pattern[, flags])
参数:
pattern : 一个字符串形式的正则表达式
flags : 可选,表示匹配模式,比如忽略大小写,多行模式等,具体参数为:
关于flags更多请参考:https://docs.python.org/zh-cn/3/library/re.html#module-contents “模块内容” 小节
下面两个正则表达式等价地匹配一个十进制数字: a = re.compile(r"""\d + # the integral part \. # the decimal point \d * # some fractional digits""", re.X) b = re.compile(r"\d+\.\d*") 三重引号("""), 创建了一个多行字符串。这样就可以将正则表达式定义放在多行中, 让它更可读
实例:
# 1. 组只匹配字母,因此组以空格划分
pattern = re.compile(r'([a-z]+) ([a-z]+)', re.I)
m = pattern.match('Hello World Wide Web')
print(m.group()) # Hello World
print(m.group(1)) # Hello
print(m.group(2)) # World
# 2. 组匹配所有字符,包括空格,因此组是不分单词的
pattern = re.compile(r'(.*) (.*)', re.I) # 第一组匹配除第二组匹配的,第二组默认匹配最后一个单词
m = pattern.match('Hello World Wide Web')
print(m.group()) # Hello World Wide Web
print(m.group(1)) # Hello World Wide
print(m.group(2)) # Web
# 3. 组匹配所有字符
pattern = re.compile(r'(.*?) (.*)', re.I) # 第一组非贪婪匹配,第二组默认匹配剩下的所有
m = pattern.match('Hello World Wide Web')
print(m.group()) # Hello World Wide Web
print(m.group(1)) # Hello
print(m.group(2)) # World Wide Web
在字符串中找到正则表达式所匹配的所有子串。
返回:一个字符串列表,包含被查找字符串中的所有匹配;如果没有找到匹配的,则返回空列表。
作为 findall()方法的返回结果的总结,请记住下面两点:
如对于findall('Cell: 415-555-9999 Work: 212-555-0000')
- 1. 如果调用在一个没有分组的正则表达式上, 例如\d\d\d-\d\d\d-\d\d\d\d, 方法findall()将返回一个匹配字符串的列表, 例如['415-555-9999', '212-555-0000']。
- 2. 如果调用在一个有分组的正则表达式上, 例如(\d\d\d)-(\d\d\d)-(\d\d\d\d), 方法 findall()将返回一个字符串的元组的列表 ( 每个分组对应一个字符串),例如[('415','555', '1122'), ('212', '555', '0000')]。
注意: match 和 search 是匹配一次, findall 匹配所有。
语法格式为:findall(string[, pos[, endpos]])
参数:
实例:查找字符串中的所有数字
import re
pattern = re.compile(r'\d+') # 查找数字
result1 = pattern.findall('runoob 123 google 456')
result2 = pattern.findall('run88oob123google456', 0, 10)
result3 = pattern.findall('run88 oob 123google456', 0, 13)
print(result1)
print(result2)
print(result3)
['123', '456']
['88', '12']
['88', '123']
re.
findall
(pattern, string, flags=0)
无法指定字符串位置
r1 = re.findall(r'\d+','runoob 123 google 456')
print(r1)
['123', '456']
['123', '456']
r2 = re.findall(r'\d+','runoob 123 google 456', 0, 10)
print(r2)
TypeError: findall() takes from 2 to 3 positional arguments but 4 were given
和 findall 类似,在字符串中找到正则表达式所匹配的所有子串,并把它们作为一个迭代器返回。
语法格式为:re.finditer(pattern, string, flags=0)
import re
it = re.finditer(r"\d+","12a32bc43jf3")
print(it)
for match in it:
print(match.group())
结果:
12
32
43
3
split 方法按照能够匹配的子串将字符串分割后返回列表,它的使用形式如下:
语法格式为:re.split(pattern, string[, maxsplit=0, flags=0])
参数:
参数 | 描述 |
---|---|
pattern | 匹配的正则表达式 |
string | 要匹配的字符串。 |
maxsplit | 分隔次数,maxsplit=1 分隔一次,默认为 0,不限制次数。 |
flags | 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。参见:正则表达式修饰符 - 可选标志 |
如果在 pattern 中捕获到括号,那么所有的组里的文字也会包含在列表里。如果 maxsplit 非零, 最多进行 maxsplit 次分隔, 剩下的字符全部返回到列表的最后一个元素。
\w:字母、数字、下划线。如果设置了 ASCII
标志,就只匹配 [a-zA-Z0-9_]
。
\W:匹配任何不是单词字符的字符。 这与 \w
正相反。 如果使用了 ASCII
旗标,这就等价于 [^a-zA-Z0-9_]
。
re.split('\W+', 'runoob, runoob, runoob.')
['runoob', 'runoob', 'runoob', '']
re.split('(\W+)', 'runoob, runoob, runoob.')
['runoob', ', ', 'runoob', ', ', 'runoob', '.', '']
re.split('(\W+)', ' runoob, runoob, runoob.') # 若开头、结尾有非w字符,则结果开头和结尾包含''
['', ' ', 'runoob', ', ', 'runoob', ', ', 'runoob', '.', '']
re.split('(\W+)', 'runoob runoob, runoob') # 若开头、结尾没有非w字符,则结果开头和结尾不包含''
['runoob', ' ', 'runoob', ', ', 'runoob']
re.split('(\W+)', ' runoob runoob, runoob')
['', ' ', 'runoob', ' ', 'runoob', ', ', 'runoob']
re.compile() 返回 RegexObject 对象。
group() 返回被 RE 匹配的字符串。
pattern = re.compile(r'\d+')
pattern # re.compile(r'\d+', re.UNICODE)
m2 = pattern.match(s, 3,10)
m2 #
正则表达式可以包含一些可选标志修饰符来控制匹配的模式。修饰符被指定为一个可选的标志。多个标志可以通过按位 OR(|) 它们来指定。如 re.I | re.M 被设置成 I 和 M 标志:
修饰符 | 描述 |
---|---|
re.I | 使匹配对大小写不敏感 |
re.L | 做本地化识别(locale-aware)匹配 |
re.M | 多行匹配,影响 ^ 和 $ |
re.S | 使 . 匹配包括换行在内的所有字符 |
re.U | 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B. |
re.X | 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。 |
'(?P...)' 分组匹配
例:身份证 1102231990xxxxxxxx
import re
s = '1102231990xxxxxxxx'
res = re.search('(?P\d{3})(?P\d{3})(?P\d{4})',s)
print(res.groupdict()) # 直接将匹配结果直接转为字典模式,方便使用。
{'province': '110', 'city': '223', 'born_year': '1990'}