21. re模块
一、正则
1. 字符
元字符 | 匹配内容 |
---|---|
. | 匹配出换行外任意字符 |
\w | 匹配字母或数字或下划线 |
\s | 匹配任意空白符 |
\d | 匹配数字 |
\n | 匹配一个换行符 |
\t | 匹配一个制表符 |
\b | 匹配一个单词的结尾 |
^ | 匹配指定字符的开始 |
$ | 匹配字符串的结尾 |
\W | 匹配非字母数字下划线 |
\D | 匹配非数字 |
\S | 匹配非空白符 |
a | b | 匹配字符a或字符b |
() | 匹配括号内的表达式,也是一个组 |
[...] | 匹配字符组中的字符 |
[^...] | 匹配除了字符组中的字符其他所有字符 |
2. 量词
量词 | 匹配内容 |
---|---|
* | 重复0或更多次 |
+ | 重复1或更多次 |
? | 重复0或1次 |
重复n次 | |
重复n或更多次 | |
重复n到m次 |
3. 运用
import re
string_test = "hello"
(1) .
string_1 = re.findall('.', string_test)
print(string_1)
>['h', 'e', 'l', 'l', 'o']
(2) ^
string_2 = re.findall('^h', string_test)
print(string_2)
>['h']
(3) $
string_3 = re.findall('o$', string_test)
print(string_3)
>['o']
(4) * - 当匹配单个字符的时候,会因为匹配0次而出现空字符
string_test = "hello llo lw"
string_1 = re.findall('l*', string_test)
print(string_1)
>['', '', 'll', '', '', 'll', '', '', 'l', '', '']
string_test = "hello llo lw"
string_1 = re.findall('ll*', string_test)
print(string_1)
>['ll', 'll', 'l']
(5) +
string_test = "hello llo lw"
string_1 = re.findall('l+', string_test)
print(string_1)
>['ll', 'll', 'l']
string_test = "hello llo lw"
string_1 = re.findall('ll+', string_test)
print(string_1)
>['ll', 'll']
(6) ?
string_test = "hello llo lw"
string_1 = re.findall('l?', string_test)
print(string_1)
>['', '', 'l', 'l', '', '', 'l', 'l', '', '', 'l', '', '']
string_test = "hello llo lw"
string_1 = re.findall('ll?', string_test)
print(string_1)
>['ll', 'll', 'l']
(7) {n, }
str1='iii amiiii ssdii iihjf iiifgfdgi '
str2=re.findall('ii{2,}',str1)
print(str2)
>['iii', 'iiii', 'iii']
(8) {, m}
str1='iii amiiii ssdii iihjf iiifgfdgi '
str2=re.findall('ii{,2}',str1)
print(str2)
>['iii', 'iii', 'i', 'ii', 'ii', 'iii', 'i']
(9) {n, m}
str1='iii amiiii ssdii iihjf iiifgfdgi '
str2=re.findall('ii{1,2}',str1)
print(str2)
>['iii', 'iii', 'ii', 'ii', 'iii']
(10) \d
str1='iii amiiii 123er45vg44 '
str2=re.findall(r'\d',str1)
print(str2)
>['1', '2', '3', '4', '5', '4', '4']
(11) \w
str1='iii am_你好iiii 123er45vg44 '
str2=re.findall(r'\w',str1)
print(str2)
>['i', 'i', 'i', 'a', 'm', '_', '你', '好', 'i', 'i', 'i', 'i', '1', '2', '3', 'e', 'r', '4', '5', 'v', 'g', '4', '4']
(12) \s
str1='iii am_你好iiii 123\ner\t45vg44 '
str2=re.findall(r'\s',str1)
print(str2)
>[' ', ' ', '\n', '\t', ' ']
(13) \b
str1='i love python '
str2=re.findall(r'\bon',str1)
str3=re.findall(r'on\b',str1)
print(str2)
print(str3)
>[]
>['on']
(14) \D
str1='i love python12456'
str2=re.findall(r'\D',str1)
print(str2)
>['i', ' ', 'l', 'o', 'v', 'e', ' ', 'p', 'y', 't', 'h', 'o', 'n']
(15) \S
str1='i love python12456\n\t'
str2=re.findall(r'\S',str1)
print(str2)
>['i', 'l', 'o', 'v', 'e', 'p', 'y', 't', 'h', 'o', 'n', '1', '2', '4', '5', '6']
(16) \W
str1='i love ¥%*python12456\n\t'
str2=re.findall(r'\W',str1)
print(str2)
>[' ', ' ', '¥', '%', '*', '\n', '\t']
(17) \B
str1='i love python12456'
str2=re.findall(r'ov\B',str1)
print(str2)
>['ov']
(18) []字符集
str1='i love python12456'
str2=re.findall(r'[a-z]',str1)
print(str2)
>['i', 'l', 'o', 'v', 'e', 'p', 'y', 't', 'h', 'o', 'n']
str1='i love python12456'
str2=re.findall(r'[^\d]',str1)
print(str2)
>['i', ' ', 'l', 'o', 'v', 'e', ' ', 'p', 'y', 't', 'h', 'o', 'n']
(19) |
str1='i love python12456\n\n'
str2=re.findall(r'[\d|\s]',str1)
print(str2)
>[' ', ' ', '1', '2', '4', '5', '6', '\n', '\n']
(20) () 分组-标记一个子表达式的开始和结束位置。子表达式可以获取供以后使用。只会匹配括号中的内容
str1='i love python12456\n\n'
str2=re.findall(r'n(\d)',str1)
print(str2)
>['1']
二、贪婪与非贪婪匹配
正则表达式通常用于在文本中查找匹配的字符串。Python里数量词默认是贪婪的(在少数语言里也可能是默认非贪婪),总是尝试匹配尽可能多的字符;非贪婪则相反,总是尝试匹配尽可能少的字符。在"*","?","+","{m,n}"后面加上?,使贪婪变成非贪婪。
1. 贪婪模式
贪婪模式下字符串查找会直接走到字符串结尾去匹配,如果不相等就向前寻找,这一过程称为回溯
import re
str1='<table><td><th>贪婪</th><th>贪婪</th><th>贪婪</th></td></table>贪婪'
str2=re.findall(r'<.*>',str1)
print(str2)
>['<table><td><th>贪婪</th><th>贪婪</th><th>贪婪</th></td></table>']
2. 非贪婪模式
非贪婪模式下会自左向右查找,一个一个匹配不会出现回溯的情况
import re
str1='<table><td><th>贪婪</th><th>贪婪</th><th>贪婪</th></td></table>贪婪'
str2=re.findall(r'<.*?>',str1)
print(str2)
>['<table>', '<td>', '<th>', '</th>', '<th>', '</th>', '<th>', '</th>', '</td>', '</table>']
三、re模块使用
1. re.A(re.ASCII)
让\w,\W,\b,\B,\d,\D,\s和\S 执行ASCII-只匹配完整的Unicode匹配代替。这仅对Unicode模式有意义,而对于字节模式则忽略。
2. re.I(re.IGNORECASE)
执行不区分大小写的匹配;类似的表达式也[A-Z]将匹配小写字母。
3. re.L(re.LOCALE)
让\w,\W,\b,\B和区分大小写的匹配取决于当前的语言环境。该标志只能与字节模式一起使用。不建议使用此标志,因为语言环境机制非常不可靠,它一次只能处理一种“区域性”,并且仅适用于8位语言环境。默认情况下,Python 3中已为Unicode(str)模式启用了Unicode匹配,并且能够处理不同的语言环境/语言。
4. re.M(re.MULTILINE)
指定时,模式字符'^'在字符串的开头和每行的开头(紧随每个换行符之后)匹配;模式字符'$'在字符串的末尾和每行的末尾(紧接在每个换行符之前)匹配。默认情况下,'^' 仅在字符串的开头,字符串'$'的末尾和字符串末尾的换行符(如果有)之前立即匹配。
5. re.S(re.DOTALL)
使'.'特殊字符与任何字符都匹配,包括换行符;没有此标志,'.'将匹配除换行符以外的任何内容。
1. findall(pattern, string, flags=0)
findall方法,该方法在字符串中查找模式匹配,将所有的匹配字符串以列表的形式返回,如果文本中没有任何字符串匹配模式,则返回一个空的列表,如果有一个子字符串匹配模式,则返回包含一个元素的列表,所以,无论怎么匹配,我们都可以直接遍历findall返回的结果而不会出错。
import re
re_str = "hello this is python 2.7.13 and python 3.4.5"
pattern = "python [0-9]\.[0-9]\.[0-9]"
result = re.findall(pattern=pattern, string=re_str)
print(result)
>['python 2.7.1', 'python 3.4.5']
# 忽略大小写
re_str = "hello this is python 2.7.13 and Python 3.4.5"
pattern = "python [0-9]\.[0-9]\.[0-9]"
result = re.findall(pattern=pattern, string=re_str, flags=re.IGNORECASE)
print(result)
>['python 2.7.1', 'Python 3.4.5']
2. re.compile(pattern, flags=0)
一般采用编译的方式使用python的正则模块,如果在大量的数据量中,编译的方式使用正则性能会提高很多
import re
re_str = "hello this is python 2.7.13 and Python 3.4.5"
re_obj = re.compile(pattern = "python [0-9]\.[0-9]\.[0-9]",flags=re.IGNORECASE)
res = re_obj.findall(re_str)
print(res)
>['python 2.7.1', 'Python 3.4.5']
3. re.match(pattern, string, flags=0)
match方法,类似于字符串中的startwith方法,只是match应用在正则表达式中更加强大,更富有表现力,match函数用以匹配字符串的开始部分,如果模式匹配成功,返回一个SRE_Match类型的对象,如果模式匹配失败,则返回一个None,因此对于普通的前缀匹配
1. 判断data字符串是否以what、数字开头
import re
s_true = "what is a boy"
s_false = "What is a boy"
re_obj = re.compile("what")
print(re_obj.match(string=s_true))
><_sre.SRE_Match object; span=(0, 4), match='what'>
print(re_obj.match(string=s_false))
>None
2. 匹配数字
s_true = "123what is a boy"
s_false = "what is a boy"
re_obj = re.compile("\d+")
print(re_obj.match(s_true))
><_sre.SRE_Match object; span=(0, 3), match='123'>
print(re_obj.match(s_true).start())
>0
print(re_obj.match(s_true).end())
>3
print(re_obj.match(s_true).string)
>123what is a boy
print(re_obj.match(s_true).group())
>123
print(re_obj.match(s_false))
>None
4. re.search(pattern, string, flag=0)
search方法,模式匹配成功后,也会返回一个SRE_Match对象,search方法和match的方法区别在于match只能从头开始匹配,而search可以从字符串的任意位置开始匹配,他们的共同点是,如果匹配成功,返回一个SRE_Match对象,如果匹配失败,返回一个None,这里还要注意,search仅仅查找第一次匹配,也就是说一个字符串中包含多个模式的匹配,也只会返回第一个匹配的结果,如果要返回所有的结果,最简单的方法就是findall方法,也可以使用finditer方法
print(re.search('\dcom','www.4comrunoob.5com').group())
>4com
*注:match和search一旦匹配成功,就是一个match object对象,而match object对象有以下方法:
* group() 返回被 RE 匹配的字符串
* start() 返回匹配开始的位置
* end() 返回匹配结束的位置
* span() 返回一个元组包含匹配 (开始,结束) 的位置
* group() 返回re整体匹配的字符串,可以一次输入多个组号,对应组号匹配的字符串。
import re
a = "123abc456"
print(re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(0)) #123abc456,返回整体
print(re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(1)) #123
print(re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(2)) #abc
print(re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(3)) #456
>>>group(1) 列出第一个括号匹配部分,group(2) 列出第二个括号匹配部分,group(3) 列出第三个括号匹配部分
5. re.finditer(pattern, string, flags=0)
搜索string,返回一个顺序访问每一个匹配结果(Match对象)的迭代器。找到 RE 匹配的所有子串,并把它们作为一个迭代器返回
import re
re_str = "what is a different between python 2.7.14 and python 3.5.4"
re_obj = re.compile("\d{1,}\.\d{1,}\.\d{1,}")
for i in re_obj.finditer(re_str):
print(i)
>> <_sre.SRE_Match object; span=(35, 41), match='2.7.14'>
>> <_sre.SRE_Match object; span=(53, 58), match='3.5.4'>
6. re.sub(pattern, repl, string, count)
re模块sub方法类似于字符串中的replace方法,只是sub方法支持使用正则表达式
import re
re_str = "what is a different between python 2.7.14 and python 3.5.4"
re_obj = re.compile("\d{1,}\.\d{1,}\.\d{1,}")
print(re_obj.sub("a.b.c",re_str,count=1))
>what is a different between python a.b.c and python 3.5.4
print(re_obj.sub("a.b.c",re_str,count=2))
>what is a different between python a.b.c and python a.b.c
print(re_obj.sub("a.b.c",re_str))
>what is a different between python a.b.c and python a.b.c
7、re.split(pattern, string[, maxsplit])
re模块的split方法和python字符串中的split方法功能是一样的,都是将一个字符串拆分成子字符串的列表,区别在于re模块的split方法能够; maxsplit用于指定最大分割次数,不指定将全部分割
print(re.split('\d+','one1two2three3four4five5'))
>['one', 'two', 'three', 'four', 'five', '']