re库和正则表达式

1. 什么是正则表达式

正则表达式是用来简洁表达一组字符串的表达式,常用于检查文本中是否含有指定的特征词、找出文中匹配特征词的位置、从文本中提取信息。Python中的re库是用来实现正则表达式操作的,并且该库采用raw string来表达正则表达式。

1.1. re.findall()将符合规则的字符串以列表形式返回

import re
s = 'python123pythonpython'
r = re.findall(r'python', s)
print(r)  # ['python', 'python', 'python']

2. 元字符、分组、贪婪模式和懒惰模式

2.1. 通配符.  除\n

s1 = 'python123'
s2 = 'python123\n'
s3 = 'python123\r'
r1 = re.findall(r'.', s1)
print(r1)    # ['p', 'y', 't', 'h', 'o', 'n', '1', '2', '3']
r2 = re.findall(r'.', s2)
print(r2)    # ['p', 'y', 't', 'h', 'o', 'n', '1', '2', '3']
r3 = re.findall(r'.', s3)
print(r3)    # ['p', 'y', 't', 'h', 'o', 'n', '1', '2', '3', '\r']
r4 = re.findall(r'.', s2, re.S)  # 修饰符re.S可以使.匹配包括\n在内的所有字符
print(r4)    # ['p', 'y', 't', 'h', 'o', 'n', '1', '2', '3', '\n']

2.2. ^ 表示匹配行的开始位置

s = 'love123\nloveyou\npython'
r1 = re.findall(r'^love', s)
print(r1)    # ['love']
r2 = re.findall(r'^love', s, re.M)  # 修饰符re.M表示可以匹配多行
print(r2)    # ['love', 'love']

2.3. $ 表示匹配行的结束位置

s = 'xxxyyy\nabc\nflyy'
r1 = re.findall(r'yy$', s)
print(r1)     # ['yy']
r2 = re.findall(r'yy$', s, re.M)
print('r2:', r2)     # ['yy', 'yy']

2.4. *+? 匹配前面的表达式次数分别为(0-无穷) (1-无穷) (0-1)

s = 'z\nzo\nzoo'
r1 = re.findall(r'zo*', s)   # *表示o可以出现(0-无穷)次
print(r1)    # ['z', 'zo', 'zoo']
r2 = re.findall(r'zo+', s)   # *表示o可以出现(1-无穷)次
print(r2)    # ['zo', 'zoo']
r3 = re.findall(r'zo?', s)   # *表示o可以出现0或1次。需要注意的是,'zoo'中包含'zo'
print(r3)    # ['z', 'zo', 'zo']

2.5. {}控制表达式次数

s = 'z\nzo\nzoo'
r = re.findall(r'zo{2}', s) # 表示o出现两次
print(r)    # ['zoo']

2.6. [] 控制匹配内容

s = 'test\nTesting\nzoo\nhij'
r1 = re.findall(r'[eio]', s)   # []表达或的关系,[eio]表示匹配e或i或o
print(r1)    # ['e', 'e', 'i', 'o', 'o', 'i']
r2 = re.findall(r'[e-o]', s)     # 匹配e到o之间的任意字符
print(r2)    # ['e', 'e', 'i', 'n', 'g', 'o', 'o', 'h', 'i', 'j']
r3 = re.findall(r'^[e-o]', s, re.M)    # 匹配行的开头是否有e到o之间的任意字符,多行匹配
print(r3)    # ['h']
r4 = re.findall(r'^[e-o]', s)    # 匹配行的开头是否有e到o之间的任意字符,只匹配第一行
print(r4)    # []
r5 = re.findall(r'[^e-o]', s)    # 这里的^表示'非'。匹配除了e到o之外字符
print(r5)    # ['t', 's', 't', '\n', 'T', 's', 't', '\n', 'z', '\n']

2.7. | 表示或

s = 'test\nTesting\nzoo\nhij'
r = re.findall(r'e|i|o', s)   # |表达或的关系,和[eio]一样,并且[eio]匹配更快
print(r)   # ['e', 'e', 'i', 'o', 'o', 'i']

2.8. () 表示分组,主要应用在限制多选结构的范围/分组/捕获文本/环视/特殊模式处理

s1 = 'a3da3ha3'
r1 = re.findall(r'(a3)+', s1)      # ()里面的为一个组也可以理解成一个整体
print(r1)   # ['a3', 'a3', 'a3']

s2 = 'p\npoo\nhoook'
r2 = re.findall(r'[p|h]o*', s2)    # o前面可以是p或h,o的个数可以是零到无穷多个
print(r2)   # ['p', 'poo', 'hooo']
r3 = re.findall(r'[p|h](o*)', s2)  # 先匹配'[p|h]o*',在匹配到的所有字符串中再匹配(o*)
print(r3)   # ['', 'oo', 'ooo']

s3 = 'h and w and t'
r4 = re.findall(r' and ', s3)
print(r4)    # [' and ', ' and ']
r5 = re.findall(r' (and) ', s3)    # 先匹配' and ',在匹配到的所有字符串中再匹配'and'
print(r5) # ['and', 'and']

    分组还可参考这篇博客,讲的比较详细。

  需注意的是,()表示捕获分组,()会把每个分组里的匹配的值保存起来,使用\n(n是一个数字,表示第n个捕获组的内容) ,(?:)表示非捕获分组,和捕获分组唯一的区别在于,非捕获分组匹配的值不会保存起来。

# 前瞻:
exp1(?=exp2) #后边是exp2就匹配
# 后顾:
(?<=exp2)exp1 #前边是exp2就匹配
# 负前瞻:
exp1(?!exp2) #后边不是exp2就匹配
# 负后顾:
(?<!exp2)exp1 #前边不是exp2就匹配

# 例如
s = '''char *a="hello"; char b='c'; /* this is comment */ int c=1; /* this is multiline comment */'''
r = re.findall(r'(?<=/\*).+?(?=\*/)', s, re.M | re.S)   # 查找开头是/*结尾是*/的字符串
print(r)   # [' this is comment ', ' this is multiline comment ']

  下面举5个例子:

  1、(abc|bcd|cde),表示这一段是abc、bcd、cde三者之一,顺序也必须一致

  2、(abc)? 表示这一组要么一起出现,要么不出现,出现那则按顺序出现

  3、(?:abc)表示找到一样abc的一组,但是不记录,不保存到变量中,否则可以通过x取第几个括号所匹配道德项,比如:

  (aaa)(bbb)(ccc)(?:ddd)(eee)可以用1(𝑎𝑎𝑎)1获取(aaa)匹配到的内容,而3则获取到了(ccc)匹配到的内容,而\4则获取的是由(eee)匹配到的内容,因为前一对括号没有保存变量

  4、a(?=bbb)表示a后面必须紧跟3个连续的b

  5、(?i:xxxx)不区分大小写   (?s:.*)跨行匹配,可以匹配回车符

2.9. 取消正则语法

s = 'xyz123.'
r1 = re.findall(r'.', s)     # 匹配所有字符
print(r1)   # ['x', 'y', 'z', '1', '2', '3', '.']
r2 = re.findall(r'\.', s)    # 匹配.它自己
print(r2)   # ['.']

2.10. 贪婪模式和懒惰模式[5]

2.11. 简单的总结

   

 

3. python的re库

3.1. re.match(), re.search(), re.compile()

s = 'alsdkj89239anpa2345s'
r = re.match(r'a', s).group()   # match匹配开头,group方法取出匹配到的结果,返回字符或字符串
print(r)   # a

r1 = re.search(r'\d+', s).group()   # search匹配第一个符合规则的字符串,返回字符或字符串
print(r1)   # 89239
r2 = re.findall(r'\d+', s)          # findall匹配所有符合规则的字符串,返回列表
print(r2)   # ['89239', '2345']

rec = re.compile('\d+')    # 根据字符串创建模式对象
r3 = re.findall(rec, s)
print(r3)    # ['89239', '2345']

关于re.compile(),还可参考这篇博文

3.2. re.sub()

r1 = re.sub(r'hello', 'i love the', 'hello world')
print(r1)   # i love the world

r2 = re.sub(r'(\d+)', 'hello', 'my number is 400 and door num is 200')
print(r2)   # my number is hello and door num is hello

r3 = re.sub(r'hello (\w+), nihao \1', r'emma', 'hello sherry, nihao sherry')   # \1代表第一个分组的值即sherry
print(r3)   # emma

3.3. re.split()

s1 = 'aaa bbb ccc;ddd eee,fff'
r1 = re.split(r'[;,\s]', s1)
print(r1)   # ['aaa', 'bbb', 'ccc', 'ddd', 'eee', 'fff']

s2 = ';;;'
r2 = re.split(r';', s2)
print(r2)   # ['', '', '', '']

 

参考资料:

[1].【文本分析】正则表达式

[2]. Python基础——正则表达式

[3]. 正则表达式分组

[4]. 史上最详细的正则表达式~你学会了吗? blibli

[5]. 正则表达式30分钟入门教程

[6]. python 中的 re.compile 函数

[7]. 网络爬虫与信息提取课程第7单元

posted @ 2020-04-03 11:37  Picassooo  阅读(469)  评论(0编辑  收藏  举报