正则表达式

概述

定义
正则表达式是一个特殊的字符序列,可以检测一个字符串是否与我们设定的这样的字符序列相匹配

作用
快速检索文本、实现一些替换文本的操作

比如

  1. 检查一串数字是否为电话号码
  2. 检测一个字符串是否符合email
  3. 把一个文本里指定的单词替换为另一个单词

栗子

1
2
3
4
5
6
7
8
9
a='C|C++|Java|C#|Python|Javascript'

# a.index('Python') 内置函数查找特定字符串,返回首下标

# print('Python' in a) in 操作符检测

import re #正则表达式存在的模块
r=re.findall('Python',a) #re.findall('正则表达式',源串)
print(r)
['Python']    # 返回一个列表

改写原代码

1
2
3
4
5
6
7
import re
a='C|C++|Java|C#|Python|Javascript'
r=findall('Python',a)
if len(r)>0:
print("字符串中包含Python")
else:
print('No')

正则表达式重要在规则(灵魂)上,而不是设置成常量(设置成‘Python’)

组成
正则表达式由一系列普通字符和元字符所组成

  • 普通字符 (形如前面例子中的’Python’ )
  • 元字符
    • ‘\d’ 元字符(代表数字)
    • ‘\D’ (代表非数字字符)
    • ‘\w’(匹配数字和字母和下划线)
    • ‘\W’ 匹配非单词字符(\r,\t,’ ‘)
    • ‘\s’ 匹配空白字符(空格回车制表)
    • . 匹配除换行符外所有字符

模式

字符集

[ ]中的字符集合

  • 在[]中匹配“或”的关系

      [afc]
    
  • 在[]匹配取反操作

      [^afc]
    
  • 在[]中有顺序操作

      [c-f]    # 匹配cdef
    

概括字符集

  • ‘\d’等价于[0-9]
  • ‘\D’等价于[ ^0-9 ]
  • ‘\w’等价于[A-Za-z0-9_]

只能匹配出单字符(以一个字符为单位的结果),因为元字符是字符存在

1
2
3
4
5
import re
s='abc, acc, adc,aec,afc,ahc'
#找出中间字母是a或者f的字符串
r=re.findall('a[cf]c',s) # a,c 普通字符定界,匹配出单词
print(r)
['acc','afc']

数量词

假设在’pytho0python1pythonn2’串中寻找python
表示形式

  • { } 前面单个字符的重复

      r=re.findall('[a-z]{3}',a)  # 数量词为3
      r=re.findall('[a-z]{3,6}',a)  # 支持范围,重复3-6次
    
  • *前面的字符(n)可以出现0次或者无限多次

      r=re.findall('python*',a) # 表示一个重复的操作
    
  • +前面的字符可以出现一次或者无限多次

      r=re.findall('python+',a) # 
    
  • ?前面的字符可以出现1次或者0次

      r=re.findall('python?',a) # 去重操作
    

下面是’*’,’+’,’?’的例子

1
2
3
4
5
6
7
8
import re
a='pytho0python1pythonn2'
r= re.findall('python*',a)
s= re.findall('python+',a)
t= re.findall('python?',a)
print(r)
print(s)
print(t)
['pytho','python','pythonn']
['python','pythonn']
['pytho','python','python']

贪婪与非贪婪
贪婪模式:努力寻找更多符合的条件

1
2
3
4
5
import re
a='pytho0python1pythonn2'
r= re.findall('python{1,2}',a) # 匹配前面的单字符n出现1-2次
s= re.findall('python{1,2}?',a) #非贪婪:匹配n只出现1次
print(r)
['python', 'pythonn']   # 默认贪婪
['python', 'python']    # 非贪婪

?的”非贪婪限制”和”自身意义”区别

1
2
3
4
5
6
7
8
import re
a='pytho0python1pythonn2'
r= re.findall('python{1,2}',a) # 默认为贪婪
s= re.findall('python{1,2}?',a) # ?限定非贪婪
t= re.findall('python?',a) # 自身意义(去重操作)
print(r)
print(s)
print(t)
['python','pythonn']
['python','python']
['pytho','python','python']

边界匹配

1
2
3
4
5
import re
qq='100001'
#检测4-8位QQ号
r=re.findall('^\d{4,8}$',qq)
print(r)

^:从源字符串开始匹配
$:从源字符串末尾匹配

1
2
3
4
5
6
7
8
import re
qq='10000001'
#检测4-8位QQ号
t=re.findall('000',qq)
r=re.findall('^000',qq) # 要匹配源串必须以000开头 (1开头)
s=re.findall('000$',qq) # 要匹配源串必须以000结尾 (1结尾)
print(t)
print(r)
[000,000]   # 两组000
[]          # 字符串开始匹配为非0,所以无匹配结果

1
2
3
a='PythonPythonPythonPtyhonPython'
r=re.findall('(Python){3}(JS)',a)
print(r)

()组:里面的字符为且关系,一个正则表达式中可以有多个组
[]字符集:里面字符为或关系

re.findall第三个参数

第三个参数代表 模式:
re.I 忽略第一个参数大小写
re.S .将匹配所有字符(包括换行符\n)
第三个参数中可以有多个模式 用|连接 表示 且 关系

re模块下的其他函数

re.sub()字符串替换

5个参数

  1. pattern:正则表达式(精准定位)
  2. 要替换成的新串
  3. 源串
  4. count参数:所能被替换最大次数(0默认为贪婪 全部替换)

强大部分:第二个参数可以是函数

1
2
3
4
5
6
import re
language='PythonC#JavaC#PHPC#'
def convert(value):
pass
r=re.sub('C#',convert,language)
print(r)

PythonJavaPHP      # C#被全部删除

原理:
第一个正则表达式将作为传入第二个函数
函数返回的结果将作为第二个参数

1
2
3
4
5
6
import re
language='PythonC#JavaC#PHPC#'
def convert(value):
print(value)
r=re.sub('C#',convert,language)
print(r)
<re.Match object; span=(6, 8), match='C#'>
<re.Match object; span=(12, 14), match='C#'>
<re.Match object; span=(17, 19), match='C#'>
PythonJavaPHP

通过print(value)发现,C#被传入了value object(对象)进而传入函数sub中。
span表示C#在源串中的位置(第a个字符之后,第b个字符结束)
从value中对象拿出结果C#方法

matched=value.group()  #用matched接收
1
2
3
4
5
6
7
import re
language='PythonC#JavaC#PHPC#'
def convert(value):
matched=value.group() # 提取C#
return '!!'+matched+'!!'
r=re.sub('C#',convert,language)
print(r)
Python!!C#!!Java!!C#!!PHP!!C#!!

第二个函数为参数的意义:

根据不同结果进行不同的替换操作

比如:将’ABC3721D86串中的大于6的数字替换成9,小于等于6的数字替换成0

1
2
3
4
5
6
7
8
9
10
import re
language='ABC3721D86'
def convert(value):
matched=value.group()
if int(matched)>6: # 传入函数的是字符
return '9'
else:
return '0' # 返回字符串的应该是字符串,不能直接返回int型数字
r=re.sub('\d',convert,language)
print(r)

ABC0900D90

输入函数的是一个字符串,return回来的也须是一个字符串

match()函数和search()函数

match():从源字符串首字母开始匹配,如果没有匹配,则返回None
search():搜索整个字符串,若找到第一个匹配字符串,返回一个对象。
如果要读取对象返回的结果

r.group()

如果要读取返回的位置

r.span()

match()和search()都只会匹配一次,findall()会找出所有匹配结果

group分组

提取字符串’life is short, i use python’中life和python之间的内容

1
2
3
4
import re
s='life is short, i use python'
r=re.search('life(.*)python',s) # .*定位除了换行符外所有字符 (*:重复操作)
print(r.group(1))
 is short, i use 

group():

  • 可以传入一个参数,指定获取的组号,默认group(0)
  • 若要访问内部分组,从group(1)开始
    (group(0)属于特殊情况:永远记录正则表达式完整匹配结果)
  • 可同时访问多个组号
      print(r.group.(0,1,2))  # 以元组形式返回
    

groups():

只会返回中间()匹配项

1
2
3
4
5
import re
s='life is short, i use python, i love python'
r=re.search('life(.*)python(.*)python',s)
print(r.group(0,1,2))
print(r,groups())
('life is short, i use python, i love python', ' is short, i use ', ',i love ')
(' is short, i use ', ', i love ')