正则表达式
一、search()和match()的区别:
re.search 扫描整个字符串并返回第一个成功的匹配。可以在任何位置匹配。
re.search(pattern, string, flags=0)
re.match 尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none。
re.match(pattern, string, flags=0)
如果:pattern = '^...' 这里加了一个开始限定符 ^ ,那么search和match作用一样。
注意:search( ) 和 match() 都只能匹配一次,匹配到结果后立即返回,要匹配多次请看下面:
二、findall() 和 finditer()
可以匹配多次
import re text = '你们好Hello好你234\n1ddsdf2在llo好' p = '好' print(re.findall(p,text)) # 返回一个list ['好', '好', '好'] m = re.finditer(p,text) print(m) # <class 'callable_iterator'> for i in m: print(i) # <re.Match object; span=(8, 9), match='好'> print(i.group()) # -------------------------------- s = 'ddabcabcabceee' r = '(abc){3}' print(re.findall(r, s)) # ['abc'] r = '(?:abc){3}' print(re.findall(r, s)) ['abcabcabc']
三、检索和替换
Python 的re模块提供了re.sub用于替换字符串中的匹配项。
语法:re.sub(pattern, repl, string, count=0, flags=0)
参数:
pattern : 正则中的模式字符串。
repl : 替换的字符串,也可为一个函数。
string : 要被查找替换的原始字符串。
count : 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。
flags : 编译时用的匹配模式,数字形式。
#!/usr/bin/python3 import re phone = "2004-959-559 # 这是一个电话号码" # 删除注释 num = re.sub(r'#.*$', "", phone) print ("电话号码 : ", num) # 移除非数字的内容 num = re.sub(r'\D', "", phone) print ("电话号码 : ", num)
输出:电话号码 : 2004-959-559 电话号码 : 2004959559
repl 参数是一个函数
以下实例中将字符串中的匹配的数字乘于 2:
import re # 将匹配的数字乘于 2 def double(matched): value = int(matched.group('value')) return str(value * 2) s = 'A23G4HFD567' print(re.sub('(?P<value>\d+)', double, s))
执行输出结果为:A46G8HFD1134
四、split( ) 字符串分隔:结果将返回一个list。
注意:split() str和re都有该方法,该方法中的第一个参数可以是str,也可以是pattern(正则表达式模式)
字符串分割使用 split()函数, 该函数按照匹配的子字符串进行字符串分割,返回字符串列表 (list) 对象。
re.split(pattern, string, maxsplit=0 , flags=0)
五、compile 函数
为了提高效率, 还可以对 Python 正则表达式进行编译。编译的正则表达式可以重复使用 ,这样能减少正则表 达式的解析和验证,提高效率
compile 函数用于编译正则表达式,生成一个正则表达式( Pattern )对象,供 match() 和 search() 这两个函数使用。
语法格式为:
re.compile(pattern[, flags])
注意:编译参数flags(可选)要在编译的时候就写进去,编译以后,方法 search()、 match()、 findall() 和 finditer() 中的参数为:
string[, pos[, endpos],多了两个可选参数:pos 和 endpos
pos 为开始查找的索引 , 参数 endpos 为结束查找的索引
因为索引可以自定义,因此:编译后的match()可以指定匹配位置,不一定非得从第一个字符开始匹配
import re phone = "2004-959-559 # 这是一个电话号码" # 非数字的内容 p = '\D' regex = re.compile(p, flags=re.M) # 编译标志flags为可选 print(type(regex)) # <class 're.Pattern'> match = regex.match(phone, 13) # 可以定义索引起始范围
六、编译标志 flags
flags 可选,表示匹配模式,比如忽略大小写,多行模式等,具体参数为:
re.I 忽略大小写
re.A 只匹配ASCII码
re.L 表示特殊字符集 \w, \W, \b, \B, \s, \S 依赖于当前环境
re.M 多行模式 多行模式对于元字符 ^ 和 $ 行 为会产生影响。默认情况下^ 和$ 匹配字符串的开始和结束,而在多行模式下 ^ 和 $ 匹配任意 一行的开始和结束
re.S 或 re.DOTALL 即为' . '包括换行符在内的任意字符(' . '本来是不包括换行符)
re.U 表示特殊字符集 \w, \W, \b, \B, \d, \D, \s, \S 依赖于 Unicode 字符属性数据库 ,可以匹配汉字
re.X 或 re.VERBOS 详细模式,为了增加可读性,忽略空格和' # '后面的注释
当需要设置多 编译标志时, 编译标志之间需要位或运算符“ |”
七、一个完整的例子:
import re s = "+aaa.jpg,bbb.jpg,ccc.bmp" # r = r"\w+(?:.jpg)" # findall能捕获到整个表达式,math.group(1)将抛出错误,因为没有可以捕获的组。 r = r"\w+(.jpg)" # findall只能捕获到括号里面的 r = r"\w+(?:.jpg)" # ?: 表示非捕获模式 math = re.search(r, s) # search()可以从任意位置开始匹配, # math = re.match(r, s) # match() 必须从开头开始匹配,相当于search('^xxxxxx',....) print(math) # <re.Match object; span=(1, 8), match='aaa.jpg'> print(math.span()) # (1, 8) 匹配范围 print(math.start()) # 1 开始 print(math.end()) # 8 结束 print(math.group()) # aaa.jpg 无论是不是捕获模式,都能匹配整个表达式。 # print(math.group(1)) # .jpg ?:非捕获模式下出错:IndexError: no such group print(math.groups()) # ('.jpg',) ?:非捕获模式下:() # 说明:findall捕获到的是组(即括号里面的),没有组时能捕获到整个表达式。 list = re.findall(r, s) print(type(list)) # <class 'list'> print(list) # ['.jpg', '.jpg'] ?:非捕获模式下:() ['aaa.jpg', 'bbb.jpg'] r = '34|2b|1d' # 34 或者 2b 或者 1d # r = '[34bd]' # 3或4或b或d,其中的任意一个 r = '[(34)(bd)]' # 等价于 '[34bd]',()没有任何意义。同理,[(34bd)],[^(34)(bd)]的小括号也没有意义,总结:[]里面的()没有意义。 r = '[^012345]' # 不能是[]里面的任意一个, # ???不能包含ab 和cd怎么写。 # 截取aaa前面的字符 s = 'a121v121faaa111' r = '(\w+)aaa' print(re.search(r, s).group(1)) # r = '(121)(12)' # math= re.search(r, s) # print(math.group()) # 12112 # print(math.group(2)) # 12 # print(math.groups()) # ('121', '12') s = "f<abc>ff<abc>8888888<cba>dd<cba>2fdd" r = '<abc>(?!.+<abc>).+?<cba>' print(re.findall(r, s)) print(re.search(r, s)) r = r"\w+@qq\.com" s = "2833@qq.com asdfsdf@qq.com" regex = re.compile(r) m1 = regex.search(s, 8) # 从第8个字符开始的任意位置匹配 m = regex.match(s, 2) # 从第2个字符开始匹配。 print(m1)
非捕获模式
import re # 关于正则表达式的捕获模式。 # 模式一: # (pattern) 平时最常用的模式,在此不作过多解释。 # 模式二:(非捕获组) # (?:pattern) 匹配但不捕获匹配结果。也就是说这是一个非捕获匹配,不存储供以后使用的匹配。否则可能会被$1或\1捕获到 # 模式三:其实也是非捕获组的扩展。 # (?=pattern) 正向预查,在任何匹配pattern的字符串开始处匹配查找字符串.这是一个非捕获匹配 # .例如:/windows(?=95|98|2000)/能匹配windows2000中的windows,但不能匹配windowsNT中的windows。 # 预查不消耗字符。例: # 模式四:其实也是非捕获组的扩展。 # (?!pattern) 反向预查。!就是不包括,不等于的意思,例: # 预查不消耗字符。例: # 以下列出 ?=、?<=、?!、?<!= 的使用区别 # 本文采用findall()查找,如果是search()的话只查找到所有匹配项的第一个。 # exp1(?=exp2):查找 exp2 前面的 exp1。 # (?=exp2)exp1:不常用,相当于查找exp2开头的exp1 # exp1(?!exp2):查找后面不是 exp2 的 exp1。 # (?!exp2)exp1:查找不是exp2开头的exp1 # (?<=exp2)exp1:查找 exp2 后面的 exp1。 # exp1(?<=exp2):查找exp2结束的exp1 # (?<!exp2)exp1:查找前面不是 exp2 的 exp1。 # exp1(?<!exp2):查找不是 exp2结尾 的 exp1。 # 说明: # 1、(?=exp2)可以理解为把边界定位到exp2前面,然后根据exp1所在的位置决定在边界前或边界后查找。 print(re.findall(r'.+(?=aa)', '123aa456aa789aa258')) # ['123aa456aa789'] 因为前面的exp1(.+)是贪婪模式,所以查找最后面的aa print(re.findall(r'.{3}(?=aa)', '123aa456aa789aa258')) # ['123', '456', '789'] # r'(?=aa).+' 相当于 r'aa.+' # r'(?=aa).{3}' 相当于 r'aa.{1}' # 不定长边界:边界前有限定符* + 这里要注意的是边界都是非贪婪的,懒惰模式 # 所以:下面的(?=.+aa)等同于(?=.+?aa) print(re.findall(r'.+(?=.+aa)', '123aa456aa789aa258')) # ['123aa456aa78'] 注意,没输出9,(?=.+aa), .+只占用一个字符,所匹配的其实是9aa print(re.findall(r'.{3}(?=.+aa)', '123aa456aa789aa258')) # ['123', 'aa4', '56a', 'a78'] (?=.+aa)边界分别对应:aa456aa,56aa,a789aa,9aa # exp1(?!exp2):查找后面不是 exp2 的 exp1。 # (?!exp2)exp1:查找不是exp2开头的exp1 print(re.findall(r'.+(?!aa)', '123aa456aa789aa258')) # ['123aa456aa789aa258'] 因为前面的exp1(.+)是贪婪模式,258后面没有aa print(re.findall(r'.{3}(?!aa)', '123aa456aa789aa258')) # ['23a', 'a45', '6aa', '89a', 'a25'] # 下面两行查找不是aa开头的字符串 # print(re.findall(r'(?!aa).+', '123aa456aa789aa258')) # ['123aa456aa789aa258'] # print(re.findall(r'(?!aa).{3}', '123aa456aa789aa258')) # ['123','a45', '6aa', '789','a25] 从边界位置开始查找3个字符 print(re.findall(r'.+(?!.+aa)', '123aa456aa789aa258')) # ['123aa456aa789aa258'] print(re.findall(r'.{3}(?!.+aa)', '123aa456aa789aa258')) # ['789', 'aa2'] # (?<=exp2)exp1:查找 exp2 后面的 exp1。 # exp1(?<=exp2):查找exp2结束的exp1 # 说明: # 1、(?<=exp2)可以理解为把边界定位到exp2后面,然后根据exp1所在的位置决定在边界前或边界后查找。 print(re.findall(r'.+(?<=aa)', '123aa456aa789aa258')) # ['123aa456aa789aa'] print(re.findall(r'.{3}(?<=aa)', '123aa456aa789aa258')) # ['3aa', '6aa', '9aa'] print(re.findall(r'(?<=aa).+', '123aa456aa789aa258')) # ['456aa789aa258'] print(re.findall(r'(?<=aa).{3}', '123aa456aa789aa258')) # ['456', '789', '258'] # (?<!exp2)exp1:查找前面不是 exp2 的 exp1。 # exp1(?<!exp2):查找不是 exp2结尾 的 exp1。 # 1、(?<!exp2)可以理解为把边界定位到exp2后面,然后根据exp1所在的位置决定在边界前或边界后查找。 print(re.findall(r'.+(?<!aa)', '123aa456aa789aa258')) # ['123aa456aa789aa258'] print(re.findall(r'.{3}(?<!aa)', '123aa456aa789aa258')) # ['123', 'aa4', '56a', 'a78', 'aa2'] print(re.findall(r'(?<!aa).+', '123aa456aa789aa258')) # ['123aa456aa789aa258'] print(re.findall(r'(?<!aa).{3}', '123aa456aa789aa258')) # ['123', 'aa4', '56a', 'a78', '9aa']
例:
import re # 要示:把,替换成#,但是""双引号里面的,不能替换 str = '111,22434222,"3534533,3fgd3",44ghg44' pram =r'(".*?),(.*?")' str = re.sub(pram, '\\1$\\2', str) # 反向引用()括号里的捕获需要\\双反斜杆 str = re.sub(',', '#' ,str) str = re.sub('\$', ',' ,str) print(str) # 111#22434222#"3534533,3fgd3"#44ghg44

浙公网安备 33010602011771号