正则表达式

正则表达式

什么是正则表达式

  • 描述祖字符串排列的一套规则. 可以按照需要, 找到某一类符合某种格式的信息.

正则表达式基础知识

原子

  • 普通字符作为原子
  • 非打印字符作为原子, 所谓非打印字符, 即在字符串中用于格式控制的符号, 比如换行符(‘\n’)等等.
  • 通用字符作为原子:
    • \w 匹配任意一个字母, 数字, 下划线
    • \W 匹配除字母, 数字和下划线意外的任意一个字符
    • \d 匹配任意一个十进制数
    • \D 匹配除了十进制数以外的任意一个其他字符
    • \s 匹配任意一个空白字符
    • \S 匹配除空白字符以外的任意一个其他字符
  • 原子表, 下面详细叙述

原子表

  • 用于定义一组地位平等的原子, 然后匹配的时候会取该原子表中的任意一个原子进行匹配
  • [xyz] 表示x,y,z 均可匹配
  • [^xyz] 表示除了x,y,z 其他均满足表达式

元字符

  • 所谓元字符, 就是正则表达式中具有一些特殊含义的字符, 比如重复N次前面的字符等.
符号 含义 符号 含义
. 匹配除了换行符意外的任意字符 ^ 匹配字符串的开始位置
$ 匹配字符串的结束位置 * 匹配0,1或者多次前面的原子
? 匹配0次或者1次前面的原子 + 匹配1次或者多次前面的原子
{n} 前面的原子恰好出现n此 {n,} 前面的原子至少出现n次
{n,m} 前面的原子出现n到m次 \ 模式选择符
() 模式单元符
  • 含义多次提到前面的字符, 意思就是: x* 表示x可以出现任意次.

边界限制元字符

  • ^xyz 表示必须以xyz开头
  • xyz$ 表示必须以xyz结尾

限定符

  • x.*y 表示x,y之间可以有任意长度的任意字符.
  • cd{2} 表示cdd
  • cd{2,4} 表示c后面有2~4个d

模式选择符

使用模式选择符, 可以设置多个模式, 匹配时, 可以从中选择任意一个模式匹配. 比如:

  • “python|php” 表示python和php均满足条件

模式单元符

可以将一些原子组成一个原子. 举个例子

  • xy{2,} 表示 y 可以出现2次以上
  • 而(xy){2,} 表示 xy 这个整体出现两次以上

模式修正

所谓模式修正, 即不改变正则表达式的情况下, 通过模式修正符改变正则表达式的含义, 从而实现匹配结果的调整.

符号 含义 符号 含义
I 匹配时忽略大小写 M 多行匹配
L 做本地化识别匹配 U 根据Unicode字符集解释字符
S 让.匹配包括换行符. 即用了该模式修正之后, “.”就可以匹配任意字符了

实例:

#encoding:utf-8
import re
try:
pattern = "python"
string = "PYTHOn"
result1 = re.search(pattern,string,re.I)
result2 = re.search(pattern,string)
print("使用修正符%s"%result1)
print("如果不使用%s"%result2)
except Exception as e:
print(e)

运行结果:

使用修正符<_sre.SRE_Match object; span=(0, 6), match='PYTHOn'>
如果不使用None

贪婪模式与懒惰模式

先来看看Python中贪婪和懒惰的定义

  • 贪婪: 尽可能多的匹配
  • 懒惰: 尽可能少的匹配, 采取就近匹配的原则, 让匹配结果更为准确.
import re
try:
pattern1 = "p.*y" ##贪婪模式
pattern2 = "p.*?y" ##懒惰模式
string = "abcdefphp345pythony_py"
result1 = re.search(pattern1,string)
result2 = re.search(pattern2,string)
print(result1)
print(result2)
except Exception as e:
print(e)

结果:

<_sre.SRE_Match object; span=(6, 22), match='php345pythony_py'>
<_sre.SRE_Match object; span=(6, 14), match='php345py'>
  • 使用贪婪模式,: .*
  • 转换为懒惰模式: 相应的 .*后面加上 ?

正则表达式常见函数

re.match()函数

想要从元字符串的起始位置匹配一个模式?

match(pattern, string, flags=0)
  • flags 是对应的标志位, 可以放模式修正符等信息.
import re
string = 'apythonbcpythonoo'
pattern = '.python.'
result1 = re.match(pattern,string)
result2 = re.match(pattern,string).span()
print(result1)
print(result2)
  • 运行结果:
<_sre.SRE_Match object; span=(0, 8), match='apythonb'>
(0, 8) ##span 只显示位置信息.

re.search() 函数

一个例子看清 search函数 和 match函数的区别:

import re
string = 'asdadasapythonbcpythonoo'
pattern = '.python.'
result1 = re.match(pattern,string)
result2 = re.search(pattern,string)
print('使用match:%s'%result1)
print('使用search:%s'%result2)
  • 运行结果
使用match:None
使用search:<_sre.SRE_Match object; span=(7, 15), match='apythonb'>
  • 可以看到, match只从开始匹配, 而search是从整个string寻找. 如果开头不匹配, match一定是None, 而只要后面包括pattern, 那么search就会返回目标位置.

findall() 函数

上面两个函数只是匹配第一个成功匹配的结果, 那么如果把所有符合的内容全部找到呢?

  • 使用re.compile() 对正则表达式进行预编译
  • 编译后, 使用findall() 根据正则表达式找到匹配的全部结果.
import re
string = 'asdadasapythonbcpythonoo'
pattern = re.compile('.python.')
result = pattern.findall(string)
print(result)
  • 运行结果
['apythonb', 'cpythono']

re.sub() 函数

想根据正则表达式来实现替换某些字符串

  • sub(pattern, repl, string, count=0, flags=0)
    • pattern: 正则表达式
    • rep: 要替换成的字符串
    • string: 源字符串
    • count: 最多替换count次, 默认全部替换.
    • flags: 标志位, 用于放模式修正符
import re

string = 'Tom and tim love Jerry'
pattern = "T.m"
rep = 'Hox'
result = re.sub(pattern,rep,string,flags=re.I)
print(result)
  • 运行结果
Hox and Hox love Jerry

常见实例解析

实例1: 匹配.com 和 .cn的URL 网址

import re

pattern = "[a-zA-Z]+://[\S]+[.com|.cn]"
string = "dasdfasdfasdf http://www.baidu.comdasdfasdf"
result = re.search(pattern,string)
print(result)
  • 运行结果
<_sre.SRE_Match object; span=(14, 34),match='http://www.baidu.com'>
  • 分析:
    • URL格式: 协议 :// 域名 .com/.cn
    • 协议可以是任意长度(大于1)的字母的组合, 所以用 [a-zA-Z]+ 表示
    • 中间的域名不能使用空格以外的任意字符串, 所以用 \S+ 表示\
    • 最后用 模式选择符 表示 .com 和 .cn

实例2: 匹配电话号码

import re

string = "Hox's python number is 0351-5207923, 这是我很小的时候家里>的固话号码"
## 电话号码, 有两种, 一种是3位区号+8位数字, 另一种是4位区号+7位数字
pattern = "\d{3}-\d{8}|\d{4}-\d{7}"
result = re.search(pattern,string)
print(result)
  • 运行结果
<_sre.SRE_Match object; span=(23, 35), match='0351-5207923'>

实例3: 匹配电子邮件地址

import re

string = "Hox's email is 213162855@seu.edu.cn"
pattern = '\w+([.+-]\w+)*@\w+([.-]\w+)*\.\w+([.-]\w+)*'
result = re.search(pattern,string)
print(result)
  • 运行结果
<_sre.SRE_Match object; span=(15, 35),match='213162855@seu.edu.cn'>