一大堆文本中提取其中指定的数据,用正则表达式
1.正则表达式原则
- 正则表达式是为了找到符合某种模式的字符串
- 模式包括:是什么字符,重复多少次,在什么位置,有哪些额外的约束。
1.1 匹配单个字符与数字
匹配 | 说明 |
---|---|
. | 匹配除换行符以外的任意字符,当flags被设置为re.S时,可以匹配包含换行符以内的所有字符 |
[] | 里面是字符集合,匹配[]里任意一个字符 |
[0123456789] | 匹配任意一个数字字符 |
[0-9] | 匹配任意一个数字字符 |
[a-z] | 匹配任意一个小写英文字母字符 |
[A-Z] | 匹配任意一个大写英文字母字符 |
[A-Za-z] | 匹配任意一个英文字母字符 |
[A-Za-z0-9] | 匹配任意一个数字或英文字母字符 |
[^lucky] | []里的^称为脱字符,表示非,匹配不在[]内的任意一个字符 |
^[lucky] | 以[]中内的某一个字符作为开头 |
\d | 一个数字字符,相当于[0-9] |
\D | 一个非数字字符,相当于[^0-9] |
\w | 字母、下划线、数字中的任意一个字符,相当于[0-9A-Za-z_] |
\W | 匹配非字母、下划线、数字中的任意一个字符,相当于[^0-9A-Za-z_] |
\s | 匹配空白符(空格、换页、换行、回车、制表),相当于[ \f\n\r\t] |
\S | 匹配非空白符(空格、换页、换行、回车、制表),相当于[^ \f\n\r\t] |
- 注意:大写字母与小写字母匹配的是相反的
1.2 锚字符
- 判定是否按照规定开始或者结尾
匹配 | 说明 |
---|---|
^ | 行首匹配,和[]里的^不是一个意思 |
$ | 行尾匹配 |
\A | 字符串开头,和^的区别是\A只匹配整个字符串的开头,即使在re.M模式下也不会匹配其他行的行首 |
\Z | 字符串结尾,和$的区别是\Z只匹配整个字符串的结尾,即使在re.M模式下也不会匹配其他行的行尾 |
\b | 单词边界 |
\B | 非单词边界 |
(?=…) | 匹配…出现在之后的位置 |
(?!…) | 匹配…不出现在之后的位置 |
(?<=…) | 匹配…出现在之前的位置 |
(?<!…) | 匹配…不出现在之前的位置 |
(?() | ) |
1.3 限定符
- 指定正则表达式的一个给定组件必须要出现多少次才能满足匹配
匹配 | 说明 |
---|---|
(xyz) | 匹配()内的xyz,作为一个整体去匹配 一个单元 子存储,()表示分组,分组后可以以组为单位应用量词 |
x? | 匹配0个或者1个x,非贪婪匹配 0-1个 |
x* | 匹配0个或任意多个x ,0-多个 |
x+ | 匹配至少一个x,1-多个 |
x{n} | 确定匹配n个x,n是非负数 |
x{n,} | 至少匹配n个x |
x{n,m} | 匹配至少n个最多m个x |
x|y | |表示或的意思,匹配x或y |
1.4 修正符
值 | 说明 |
---|---|
re.I | 是匹配对大小写不敏感,即忽略大小写 |
re.M | 多行匹配,影响到^和$ |
re.S | 使.匹配包括换行符在内的所有字符 |
1.5 python常用re函数
-
查找
查找函数 说明 search 浏览整个字符串去匹配第一个,未匹配成功返回None ,返回match对象 match 从开头开始匹配,匹配成功返回一个对象,未匹配成功返回None,只返回一个 findall 返回所有匹配的字符串列表 finditer 生成迭代器对象,包含所有的匹配,需要遍历才能得到里面的每一个数据 -
替换
函数 说明 sub 替换匹配的字符串,返回替换完成的文本 subn 替换匹配的字符串,返回替换完成的文本 和替换的次数 -
分割
函数 说明 split 根据匹配成功的位置分割 ,即用匹配的字符串做分隔符分割原字符串 -
分组
group 说明 .group() 返回所有组组成的结果,即返回整体 ,相当于.group(0) .groups() 以元祖的形式返回所有组数据 .group(number) 返回数据的第几组 -
Match对象相关方法
<re.Match object; span=(5, 8), match=‘abc’> 说明 data.group() 即返回整体结果 data.span() 返回匹配数据的索引范围 data.start() 返回匹配数据的开始索引 data.end() 返回匹配数据的结束索引 data.string 原数据字符串 -
其他
函数 说明 compile 预加载, 提前把正则对象加载完毕,直接把加载好的正则进行使用 (?P<名字>正则) 想要提取数据必须用小括号括起来. 可以单独起名字, 提取数据的时候. 需要group(“名字”)
1.6 贪婪与非贪婪匹配
- 贪婪模式
- 匹配尽可能多的字符
模式 | 说明 |
---|---|
.+ | 匹配换行符以外的字符至少一次 |
.* | 匹配换行符以外的字符任意次 |
- 非贪婪模式
- 尽可能少的匹配
模式 | 说明 |
---|---|
.+? | 匹配换行符以外的字符至少一次 |
.*? | 匹配换行符以外的字符任意次 |
1.7 分组
- 分组,把一个正则表达式分成几个部分,这样可以重复某个分组,或者指定两个分组必须相同等额外的要求。
正则 匹配 (…) 捕获一个组 (?P < Y >…) 捕获组名为Y (?:…) 不捕获组 (?P =Y) 匹配第Y个匹配到的组 (?#…) 注释
2.实例
2.1 字符串相关
2.1.1 文本匹配(查找)
-
'wxy’匹配文本中的wxy
import re text='你好,我叫wxy,英文名为angle,你可以叫我wxy或者angle' data_list=re.findall('wxy',text) print(data_list) #['wxy', 'wxy']
2.1.2 [abc]
-
匹配文本中的a或b或c字符
import re text='你好,我叫wxy,英文名为angle,你可以叫我wxy或者angle' data_list=re.findall('[abc]',text) print(data_list) #['a', 'a']
2.1.3 [^abc]
-
匹配处理abc以外的字符
import re text='你好,angle' data_list=re.findall('[^abc]',text) print(data_list) #['你', '好', ',', 'n', 'g', 'l', 'e']
2.1.4 [a-z]
import re
text='你好,angle'
data_list=re.findall('[a-z]',text)
print(data_list) #['a', 'n', 'g', 'l', 'e']
2.1.5 .
import re
text='你好,angle,a\n'
data_list=re.findall('a.',text)
print(data_list)# ['an']
2.1.6 \w
import re
text = '你好,a_n_g_le\n'
data_list = re.findall('\w', text)
print(data_list) # ['你', '好', 'a', '_', 'n', '_', 'g', '_', 'l', 'e']
2.1.7 \d
import re
text='你好,2698959795用户'
data_list=re.findall('\d',text)
print(data_list) #['2', '6', '9', '8', '9', '5', '9', '7', '9', '5']
2.1.8 \s
import re
text='你好\t,26989用户\n'
data_list=re.findall('\s',text)
print(data_list) #['\t', '\n']
2.2数量相关
2.2.1 *
-
0-多个
import re text='你好,我叫wxy,你可以叫我wy' data_list=re.findall('wx*y',text) print(data_list) #['wxy', 'wy']
2.2.2 +
- 1-多个
import re text = '你好,我叫wxy,你可以叫我wy,或者wxxxxy' data_list = re.findall('wx+y', text) print(data_list) # ['wxy', 'wxxxxy']
2.2.3 ?
- 0-1个
import re text='你好,我叫wxy,你可以叫我wy或wxxxy' data_list=re.findall('wx?y',text) print(data_list) #['wxy', 'wy']
2.2.4 {n}
import re
text='2698959795'
data_list=re.findall('26989\d{5}',text)
print(data_list) #['2698959795']
2.2.5{n,}
import re
text='2698959795'
data_list=re.findall('26989\d{1,}',text)
print(data_list) #['2698959795']
2.2.6 {n,m}
import re
text='2698959795'
data_list=re.findall('26989\d{1,3}',text)
print(data_list) #['26989597']
2.3.括号(分组)
2.3.1 提取数据区域
- 需要匹配扣扣邮件,查找的时候要根据qq邮件格式查找,但是最终只要qq号,即(qq号)
import re text='2698959795@qq.com' data_list=re.findall('(26989\d+)@qq.com',text) print(data_list) #['2698959795']
2.3.2 获取指定区域+或条件
import re
text='2698959795@qq.com,26989612@qq.com'
data_list=re.findall('((269895\d+|6\d+)@qq.com)',text)
print(data_list) #[('2698959795@qq.com', '2698959795'), ('6989612@qq.com', '6989612')]
2.4.python常用匹配函数
2.4.1 查找
-
findall
- 返回字符串列表
import re text='你好,我叫wxy,英文名为angle,你可以叫我wxy或者angle' data_list=re.findall('wxy',text) print(data_list) #['wxy', 'wxy']
- 返回字符串列表
-
match
- 返回match对象
import re text='你好,我叫wxy,英文名为angle,你可以叫我wxy或者angle' data_list=re.match('你好',text) print(data_list) #<re.Match object; span=(0, 2), match='你好'> print(data_list.group()) #你好
- Match对象相关方法
import re text = '你好,我叫wxy,英文名为angle,你可以叫我wxy或者angle' data = re.search(r'wxy', text) print(data.group()) # wxy print(data.span()) # (5, 8) print(data.start()) # 5 print(data.end()) # 8 print(data.string) # 你好,我叫wxy,英文名为angle,你可以叫我wxy或者angle
- 返回match对象
-
search
- 返回match对象
import re text='你好,我叫wxy,英文名为angle,你可以叫我wxy或者angle' data_list=re.search('wxy',text) print(data_list) #<re.Match object; span=(5, 8), match='wxy'> print(data_list.group()) #wxy
- 返回match对象
-
finditer
- 返回match 对象
import re result=re.finditer(r'\d+','我今年18岁, 我有200000000块') for item in result: #item.group()获取需要的数据 print(item.group())
- 返回match 对象
2.4.2 替换
-
sub
import re text = '你好,我叫wxy,你可以叫我wxy或者angle' # re.sub(正则表达式包替换的文本,替换成什么,原文本,替换几个) data_list = re.sub('wxy', '小红', text) data_list1 = re.sub('wxy', '小红', text, 1) data_list2 = re.sub(r'(wxy)', r'\1姐姐', text,1) print(data_list) # 你好,我叫小红,你可以叫我小红或者angle print(data_list1) # 你好,我叫小红,你可以叫我wxy或者angle print(data_list2) # 你好,我叫wxy姐姐,你可以叫我wxy或者angle
-
subn
- 返回值:替换后字符串,替换个数
import re text = '你好,我叫wxy,你可以叫我wxy或者angle' # re.subn(正则表达式包替换的文本,替换成什么,原文本,替换几个) data_list = re.subn('wxy', '小红', text) print(data_list) # ('你好,我叫小红,你可以叫我小红或者angle', 2)
2.4.3 分割
- split
import re text='你好,我叫wxy,你可以叫我wxy或者angle' data_list=re.split('wxy',text) data_list1=re.split('wxy',text,1) print(data_list) #['你好,我叫', ',你可以叫我', '或者angle'] print(data_list1) #['你好,我叫', ',你可以叫我wxy或者angle']
2.4.4 ()分组
-
group
- group() 同group(0)就是匹配正则表达式整体结果
- 正则表达式中没有括号,group(1)肯定不对了
- 正则表达式中的三组括号把匹配结果分成三组
- group(1) 列出第一个括号匹配部分,group(2) 列出第二个括号匹配部分,group(3) 列出第三个括号匹配部分
import re a = "123abc456" res=r"([0-9]*)([a-z]*)([0-9]*)" print (re.search(res,a).groups()) print (re.search(res,a).group()) #123abc456,返回整体 print (re.search(res,a).group(0)) #123abc456,返回整体 print (re.search(res,a).group(1)) #123 print (re.search(res,a).group(2) ) #abc print (re.search(res,a).group(3)) #456
2.4.5 其他
-
compile
import re text="我今年32岁" obj=re.compile(r'\d+') result=obj.findall(text) print(result) # ['32']
-
(?P<名字>正则)
obj=re.compile("<span id='(?P<id>\d+)'>(?P<name>.*?)</span>") result=obj.finditer(s) for item in result: id=item.group('id') name=item.group('name') print(id,name)
- 注意:re.S,可以匹配换行符
3.应用实例
3.1 判断是否为字符
a='我'
punctuation_pattern = r"[^\w\s]"
result=re.findall(punctuation_pattern,a) # 是字符则匹配出来,不是则为空
result
3.2 判断是否无中文
a='我'
pattern = re.compile(r'[\u4e00-\u9fff]+') # 匹配中文
result=re.search(pattern, a) # 无中文,则为空
result
3.3 去除字符串前后标点符号
- 去除
英文
标点符号a=",我.. " result=a.strip().strip(string.punctuation) result
- 去除
中文和英文
标点符号string="????你好,Hello,世界....." pattern = r'^[^\w\s]+|[^\w\s]+$' result = re.sub(pattern, '', string) result
4. 其他案例
题目来源:麦叔编程
4.1.固定的字符串
- 要求:确定字符串中是否有123456
import re text = '麦叔身高:178,体重:168,学号:123456,密码:9527,班级:123456' print(re.findall(r'123456', text))
4.2. 某一类单个字符
- 要求:找出所有的单个的数字
import re text = '体重:168,学号:123456' print(re.findall(r'\d', text))
4.3. 重复某一类字符
- 要求:找所有的数字,比如178,168,123456,9527等
import re text = '身高:178,体重:168,学号:123456,密码:9527' print(re.findall(r'\d+', text))
4.4. 组合查找
- 要求:找出
座机号码
import re text = '电话是18812345678,他还有一个电话号码是18887654321,他爱好的数字是01234567891,他的座机是:0571-52152166' print(re.findall(r'\d{4}-\d{8}', text))
4.5. 多种情况
- 要求:找出手机号码或者座机号码
import re # |为或,1表示手机号开头第一位为1 text = '电话是18812345678,他还有一个电话号码是18887654321,他爱好的数字是01234567891,他的座机是:0571-52152166' print(re.findall(r'\d{4}-\d{8}|1\d{10}', text))
4.6.限定位置
- 要求:在句子开头的手机号码,或座机
import re # ^开头字符 text = '18812345678,他还有一个电话号码是18887654321,他爱好的数字是01234567891,他的座机是:0571-52152166' print(re.findall(r'^1\d{10}|^\d{4}-\d{8}', text))
4.7.内部约束
- 要求:找出形如barbar, dardar的前后三个字母重复的字符串
import re # \w{3}表示3个字符,放在小括号中(\w{3})就成为一个分组 # \1表示第一个括号,其中的1就表示第1个括号 # (\1)表示它里面的内容和第1个括号里的内容必须相同,也就是说3个字符要重复出现两次。 text = 'barbar carcar harhel' print(re.findall(r'(\w{3})(\1)', text))
4.8 常见例子
- 匹配Email地址的正则表达式
res = '\w+([-+.]\w+)*@\w+([-.]\w+)*.\w+([-.]\w+)*'
- 匹配网址URL的正则表达式
res = '[a-zA-z]+://[^s]*'
- 匹配帐号是否合法(字母开头,允许5-16字母,允许字母数字下划线):
res = '^[a-zA-Z][a-zA-Z0-9_]{4,15}$'
- 匹配国内电话号码,格式为:区号-号码-分机号,分机号可能没有
res = 'd{3,4}-d{7,8}-d{3,4}|d{3,4}-d{7,8}'
- 匹配腾讯qq号
res = '[1-9][0-9]{4,}'
- 匹配中国邮政编码(6位数字)
res = '[1-9]\d{5}(?!\d)'
- 匹配身份证(15位或18位)
res = '\d{15}|\d{18}'
- 匹配ip地址
res = '\d+.\d+.\d+.\d+'
- 形如"carcar"或"barbar"等会重复的三个字符的单词
res = '(\w{3})(\1)'
- 获取以"密码:"开头的数字
res = '(?<=密码.)\d+'