正则表达式
一、在python中, 使用正则表达式, 需要导入re模块
import re
二、普通字符匹配, 使用findall
1 #字符匹配, 普通字符 2 #findall: 返回所有满足条件的列表集合 3 r = re.findall("alex", "afdafalexfqerqwrqwalexo") 4 print(r)
返回结果:
['alex', 'alex']
三、元字符
常用的元字符如下:
. ^ $ * + ? { } [ ] | ( ) \
a) . 的用法
# . : 匹配的是除了换行符以外的任意字符, 一个点代表一个字符 print( re.findall( "lxl.l", "fqewruolxlwlqwelxlxl" ) ) print( re.findall( "lxl..l", "fqewruolxlewlqwelxlxl" ) )
执行结果
['lxlwl', 'lxlxl']
b) ^的用法
# ^:以**开始的字符串 print( re.findall( "^lxl", "lxlqrqreqlxlasss" ) )
执行结果
['lxlewl']
c) $的用法
# $:以**结尾的字符串 print( re.findall( "lxl$", "rqreqlxlassslxl" ) )
执行结果
['lxl']
d) * 的用法
print( "=== *: 匹配前面的字符出现0个或多个字符 (贪婪匹配) =====" ) print( re.findall( "lxl*", "afdafdlxl" ) ) print( re.findall( "lxl*", "afdafdlxlaaa" ) ) print( re.findall( "lxl*", "afdafdlxlllllllsvblxbbblxl" ) )
执行结果:
['lxl'] ['lxl'] ['lxlllllll', 'lx', 'lxl']
e) + 的用法
print( "=== +: 匹配前面的字符出现1个或多个字符 (贪婪匹配) =====" ) print( re.findall( "lxl+", "afdafdlxaaaalxlllll" ) ) print( re.findall( "lxl+", "afdafdlxlaaa" ) ) print( re.findall( "lxl+", "afdafdlxlllllllsvblxbbblxl" ) )
执行结果:
['lxlllll'] ['lxl'] ['lxlllllll', 'lxl']
f) ? 的用法
print( "=== ?: 匹配前面的字符出现0个或1个字符(贪婪匹配) =====" ) print( re.findall( "lxl?", "afdafdlxlaaaalxlllll" ) ) print( re.findall( "lxl?", "afdafdlx" ) ) print( re.findall( "lxl?", "afdafdlxlllllllsvblxbbblxl" ) )
执行结果:
['lxl', 'lxl'] ['lx'] ['lxl', 'lx', 'lxl']
g) \ 的用法
print( "=== \: a. 反斜杠后面跟元字符,去除特殊功能. " " b. 反斜杠后面跟普通字符, 实现特殊功能 " " c. 引用序号对应的组所匹配的字符串" "=====" ) ''' \d: 匹配任何十进制数, 他相当于使用字符集[0-9] \D: 匹配任何非数字字符, 他相当于使用字符集[^0-9] \s: 匹配任何空白字符, 他相当于[ \t\n\r\f\v] \S: 匹配任何非空白字符, 它相当于 [^ \t\n\r\f\v] \w: 匹配任何字母数字字符, 相当于 [a-zA-Z1-9_] \W: 匹配任何非字母数字字符, 相当于[^a-zA-Z1-9_] \b: 匹配一个单词边界, 也就是单词和空格间的位置 ''' print( re.findall( "\d", "a2ff3a,aaa^lx3$lll6sll" ) ) print( re.findall( "\D\D", "a2ff3a,aaa^lx3$lll6sll" ) ) print( re.findall( "\w", "a2ff3a,aaa^lx3$lll6sll" ) ) print( re.findall( "\W", "a2ff3a,aaa^lx3$lll6sll" ) ) print( re.findall( "\s", "a2ff3a, aaa^lx3$lll6sll" ) ) print( re.findall( r"\babc\b", " abc sfasfqerqwrfasf" ) ) print( "====== c. 引用序号对应的组所匹配的字符串 =======" ) # 分析: 第一个组是alex,第二组是eric, 然后后面接com. \2表示在这个位置匹配第二个组的内容 print( re.search( r"(alex)(eric)com\2", "alexericcomeric" ).group() )
print( "=== {}: 手动设置匹配字符出现的个数 =====" ) print( re.findall( "lxl{1}", "afdafdlxlaaaalxlllll" ) ) print( re.findall( "lxl{1,5}", "afdafdlxlllxasdfqlxlioplxlliiiilxlllllll" ) ) print( re.findall( "lxl{0}", "afdafdlxlllllllsvblxbbblxl" ) )
print( "=== (): 将其里面的内容作为一个组 =====" ) print( re.findall( "lxl{1}", "afdafdlxlaaaalxlllll" ) ) print( re.findall( "lxl{1,5}", "afdafdlxlllxasdfqlxlioplxlliiiilxlllllll" ) ) print( re.findall( "lxl{0}", "afdafdlxlllllllsvblxbbblxl" ) )
print( "=== []: 字符集. 选择性匹配[]中的内容 =====" ) print( re.findall( "a[bc]d", "wwwabd" ) ) print( re.findall( "a[bc]d", "wwwacd" ) ) print( re.findall( "a[bc]d", "wwwabcd" ) ) print( re.findall( "a[bc]d", "wwwad" ) )
# 注意: 当前面说的. ? + * 放到字符集[]里面就失去意义了 print( re.findall( "a[.]d", "wwwaqd" ) ) print( re.findall( "a[.]d", "wwwa.d" ) ) # 但是,有几个字符在字符集里还是有特殊意义的 # 1. - :表示从哪到哪, 例如a-z, 从a到z; 1-9, 从1到9 print( re.findall( "a[a-z]m", "reqwasmadfazmfasm" ) ) # 2. ^ : 表示除了***,即取非. print( re.findall( "a[^1-9]", "fafa2adfa0fadfa8fafda3afa0" ) ) # af ad ad af af # 3. \ : 保留其自身的含义. print( re.findall( "\d", "adfa312dfa9adf83dfa-98" ) )
h) 贪婪模式
print( "=== 贪婪模式: * + ?都是贪婪模式, 如果去最小,则加一个? =====" ) # + 贪婪模式取最多 print( re.findall( "a\d+", "a25423bqa3423dsfa967a" ) ) # +? 则最小匹配 print( re.findall( "a\d+?", "a25423bqa3423dsfa967a" ) ) print( re.findall( "a\d*?", "a25423bqa3423dsfa967a" ) ) # 如果?后面还有内容, 则不能做到最小匹配 print( re.findall( "a\d+?b", "a25423bqa3423dsfa967a" ) ) print( re.findall( "a\d*?b", "a25423bqa3423dsfa967a" ) )
i) re 模块常用方法
''' re.findall:有() 匹配的是()里的内容 re.search: 找符合条件的第一个,第一个可以在任何位置 re.match:尝试从字符串的起始位置匹配一个模式, 如果不是起始位置匹配成功, match返回none re.sub: 替换 re.subn: 替换后返回替换次数 re.compile: 编译 re.split: 分割 re.finditer: 类似于findall, 不同之处在于finditer返回的是一个迭代器 '''
# findall 找到符合条件的全部字符串de集合 print( re.findall( "abc", "a25423bqabc3423dsfa967abc" ) ) # 返回 :['abc', 'abc'] # search 找到符合条件的第一个, 可以在任何位置的第一个. 如果没有匹配,返回None print( re.search( "abc", "a25423bqa3423abcdsfa967abc" ).group() ) # 返回:abc print( re.search( "abc", "ab" ) ) # 返回:None # match 找到符合条件的第一个, 必须在开头位置 print( re.match( "com", "abccomddd" ) ) # 返回None print( re.match( "com", "comabcddd" ).group() ) # 返回com
# 注意: 一旦search和match匹配成功以后, 就会返回一个match object对象, # 而match object对象有以下方法 ''' .start()返回匹配开始的位置 .end() 返回匹配结束的位置 .span() 返回一个元祖包含匹配(开始,结束)的位置 ·group()返回被RE匹配的字符串, 可以传递一个或多个参数,返回对应组号匹配的字符串 ''' a = "abc123def" print( re.match( "([a-z]*)([1-9]*)([a-z]*)", a ).group() ) # 匹配全部内容 结果:abc123def print( re.match( "([a-z]*)([1-9]*)([a-z]*)", a ).group( 0 ) ) # 默认参数是0, 和没有参数结果一致 print( re.match( "([a-z]*)([1-9]*)([a-z]*)", a ).group( 1 ) ) # 获取第一个组的内容 结果:abc print( re.match( "([a-z]*)([1-9]*)([a-z]*)", a ).group( 2 ) ) # 获取第二个租的内容 结果:123 print( re.match( "([a-z]*)([1-9]*)([a-z]*)", a ).group( 2, 3 ) ) # 获取第二个,第三个组的内容 结果:('123', 'def') matchObject = re.match( "([a-z]*)([1-9]*)([a-z]*)", a ) # .start 第二个组的开始位置 返回结果: 3 print( matchObject.start( 2 ) ) # end 第一个组的结束位置 返回结果:3 print( matchObject.end( 1 ) ) # span 第二个组开始位置和结束位置 返回结果是(3, 6) print( matchObject.span( 2 ) )
# re.sub: 替换 # re.sub(pattern, repl, str, max=0, flags=0) # re.sub("查找字符串","替换后的字符串","字符串","替换次数,默认是0,全部替换", 替换模式) print( re.sub( "g.t", "have", "I get you, I got me, I forgot u", 2 ) ) # 结果: I have you, I have me, I forgot u # re.subn: 替换, 并返回一个元祖, (替换结果, 替换次数) # re.subn(pattern, repl, str, max=0, flags=0) # re.subn("查找字符串","替换后的字符串","字符串","替换次数,默认是0,全部替换", 替换模式) print( re.subn( "g.t", "have", "I get you, I got me, I forgot u", 2 ) ) # 结果: ('I have you, I have me, I forgot u', 2) # re.compile: 给定一个正则表达式 pattern,指定使用的模式 flags 默认为0 即不使用任何模式, # 然后会返回一个 SRE_Pattern (参见 第四小节 re 内置对象用法) 对象 # 当多次调用的时候, 这个方法效率更高 reg = re.compile( ".+" ) print( reg.findall( "s" ) ) # re.split: 分割 # split(pattern, string, maxsplit=0, flags=0) reg = re.compile( r"\d+" ) print( reg.split( "fafafa2dfad4fadsf153uou", 2 ) ) # 返回结果: ['fafafa', 'dfad', 'fadsf153uou'] # 上面写法和下面等价 print( re.split( r"\d+", "fafafa2dfad4fadsf153uou" ) ) # 返回结果: ['fafafa', 'dfad', 'fadsf', 'uou'] print( re.split( "[bc]", "abcd" ) ) # 从前往后, 一个一个分割. 有顺序. 结果: ['a', '', 'd'] # re.finditer 参数和作用与 findall 一样,不同之处在于 findall 返回一个列表, finditer 返回一个迭代器 fi = re.compile("\d+") ite = fi.finditer("fafda2fadfadsf3422adfafa131dfadfa") for item in ite: print(item.group(),item.span())
j) 匹配模式
# 正则表达式匹配模式 -- 可选标志flags, 默认是0 # re.search(pattern, string, flags=0) # re.findall(pattern, string, flags=0) # re.match(pattern, string, flags=0) # re.I: 忽略大小写 print( re.match( "com", "CoM" ) ) # 结果None print( re.match( "com", "CoM", re.I ).group() ) # 结果: CoM # re.S: 改变.的匹配行为. 正常.是匹配除了换行符之外的所有字符. 使用re.S模式后, 匹配包括.在内的所有字符 print( re.findall( ".", "a$ d\n3a" ) ) # 不包含换行符, 返回结果: ['a', '$', ' ', 'd', '3', 'a'] print( re.findall( ".", "a$ d\n3a", re.S ) ) # 包含换行符, 返回结果: ['a', '$', ' ', 'd', '\n', '3', 'a']
k) 原生字符串
#regstr:原生字符串 print(re.findall("\\\\","abc\com")) # \有特殊含义, python需要转换一次, 正则表达式还要在转换一次, 所有需要四个\\\\ print(re.findall(r"\\","abc\com")) #而使用了原生字符r以后, 就避免了多次转换. 只需转换一次, 即正则表达式转换
l ) 优先捕获
#优先捕获 #在findall里面,如果正则表达式有()也就是组, 则优先取得组的内容. print(re.findall("www.(baidu|sina).com","www.baidu.com")) # 结果返回: baidu #在组的前面加一个?: 则去掉优先捕获 print(re.findall("www.(?:baidu|sina).com", "www.baidu.com")) #返回结果:www.baidu.com