python基于re模块的正则表达式

正则表达式

re.match方法

re.match尝试从字符串的起始位置匹配一个规则,匹配成功返回match对象,否则返回None。可以使用group()获取匹配成功的字符串

  • 语法:re.match(pattern, string, flags = 0)

  • 参数:

    参数 描述
    pattern 匹配的正则表达式
    string 要匹配的字符串
    flags 设置匹配方式
  • flags属性:

    修饰符 描述
    re.I 不区分大小写
    re.S 元字符( . )可以匹配行
    re.M 可以匹配到每一行开头影响^和$
    re.X 给正则添加注释
    re.U 根据Unicode字符集解析,影响\w \W \b \B

同时使用多个标志位可以使用 | 连接如:re.I | re.M

  • 使用group(num)或者groups()匹配对象函数获取表达式

    匹配对象的方法 描述
    group(num=0) 匹配的整个表达式的字符串, group0可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。
    groups() 返回一个包含所有小组字符串的元组,从1到所含的小组号
import re

str = 'python is the best language in the world'
# match 只能匹配以 XXX 开头的字符串,第一个参数是正则,第二个是需要陪陪的字符串
result = re.match('(.*) is (.*?) .*', str, re.I|re.M)
if result :
    print('匹配成功!!')
    print(result)
    print(result.group())  # 匹配成功使用group方法取出字符串
    print(result.group(1)) # 返回匹配成功的元组的第二项
    print(result.group(2))

    print(result.group(0))
    print(result.groups()) 
else:
    print('匹配失败!!')
    print(result)
    # print(result.group())  # 匹配失败,返回None 没有group()函数

运行结果:

# 匹配成功!!
<re.Match object; span=(0, 40), match='python is the best language in the world'>
python is the best language in the world
python
the
python is the best language in the world
('python', 'the')

正则表达式匹配规则

匹配字符

符号 匹配规则
. 匹配任意1个字符除了换行符\n
[abc] 匹配abc中的任意一个字符
\d
\s 匹配空白,即空格,tab键
\S 匹配非空白,除空格,tab键之类的
\w 匹配单词字符,即a-z、A-Z、0-9、_
\W 匹配非单词字符

. 的使用

匹配除了\n的任意一个字符

import re

names = '李达','李明','小王','小李','李\n'

# .的使用
pattern = '李.'
for name in names:
    res = re.match(pattern,name)
    if  res is not None:
        print(res.group())
        pass
    
# 结果:
# 李达
# 李明
# 不能匹配大数字

[]的使用

匹配括号内的一个字符可以用-表示范围:[a-z] [A-Z] [0-9a-zA-Z]

import re

names = 'hello','gold','kold','eello','qq\n'

# .的使用
pattern1 = '[heq]....'
for name in names:
    res = re.match(pattern,name)
    if  res is not None:
        print(res.group())
        pass
    
# 结果:
# hello
# eello

\d \D

\d 匹配一个数字 0-9
\D 匹配一个非数字

import re

names = 'hello','gold','kold','eello','qq\n','1ghjj',' hhh', \
  '\tvbn'

# \d \D的使用
pattern1 = '\d....'
pattern2 = '\D....'
for name in names:
    res1 = re.match(pattern1,name)
    res2 = re.match(pattern2,name)
    if  res1 is not None:
        print('\d 的结果%s'%(res1.group()))
        pass
    if  res2 is not None:
        print('\D 的结果%s'%(res2.group()))
        pass
# 结果:
# \D 的结果hello
# \D 的结果eello
# \d 的结果1ghjj

\s \S的使用

匹配一个空白字符(\n \t)

import re

names = 'hello', 'gold', 'kold', 'eello', 'qq\n', '1ghjj', ' hhh', \
    '\tvbn', '\nnmn'

# \d \D的使用
pattern1 = '\s...'
pattern2 = '\S...'
for name in names:
    res1 = re.match(pattern1, name)
    res2 = re.match(pattern2, name)
    if res1 is not None:
        print('\s 的结果%s' % (res1.group()))
        pass
    if res2 is not None:
        print('\S 的结果%s' % (res2.group()))
        pass
# 结果:
# \S 的结果hell
# \S 的结果gold
# \S 的结果kold
# \S 的结果eell
# \S 的结果1ghj
# \s 的结果 hhh
# \s 的结果       vbn
# \s 的结果
# nmn

\w \W 的使用

\w匹配字母、数字、下划线,即 a-z,A-Z,0-9,_
\W匹配不是字母、数字、下划线

import re

names = 'hello', 'gold', 'kold', 'eello', 'qq\n', '1ghjj', ' hhh', \
    '\tvbn', '\nnmn'

print(names)
# \d \D的使用
pattern1 = '\w...'
pattern2 = '\W...'
for name in names:
    res1 = re.match(pattern1, name)
    res2 = re.match(pattern2, name)
    if res1 is not None:
        print('\w的结果%s' % (res1.group()))
        pass
    if res2 is not None:
        print('\W的结果%s' % (res2.group()))
        pass
# 结果:
# ('hello', 'gold', 'kold', 'eello', 'qq\n', '1ghjj', ' hhh', '\tvbn', '\nnmn')
# \w的结果hell
# \w的结果gold
# \w的结果kold
# \w的结果eell
# \w的结果1ghj
# \W的结果 hhh
# \W的结果        vbn
# \W的结果
# nmn

匹配限定符号

符号 描述 符号 描述
* 匹配零次或多次 重复 m 次
+ 匹配一次或多次 重复 m 到 n 次,其中 n 可以省略,表示 m 到任意次
? 匹配一次或零次 至少 m 次

1、*号的使用

将* 前面的字符匹配0~无穷次
print(re.match('[a-z]*','Any'))不会报错因为会匹配0次

import re

strs = "AnybvjdfviniIj"

print(strs)
# *
pattern1 = '[A-Z][a-z]*'# 将[a-z]匹配0-无数次
res1 = re.match(pattern1, strs)
if res1 is not None:
    print('[A-Z][a-z]*的结果%s' % (res1.group()))
    pass

# 结果
# AnybvjdfviniIj
# [A-Z][a-z]*的结果Anybvjdfvini

2、+号的使用

与*号类似,匹配至少一次
print(re.match('[a-z]*','Any'))报错因为会匹配1次,而字符串里没有

print(re.match("[a-z_]+",'asd').group())

3、? 号的使用

? 前面的字符最多出现一次

import re


print(re.match("[a-z_]?",'asd').group())

# 结果
# a

4、{min.max}的使用

匹配前面的字符min~max次

import re

str = '123abc'
pattern1 = '\d{3}' # 精确匹配三次
pattern2 = '\d{1,2}' # 至少匹配1次,最多2次
pattern3 = '\d{2,}' # 至少匹配2次
result1 = re.match(pattern1, str)
result2 = re.match(pattern2, str)
result3 = re.match(pattern3, str)
print(result1.group())
print(result2.group())
print(result3.group())
# 结果
# a

一个小例子:匹配邮箱 xxxxx@163.com

import re

str = input("请输入您的邮箱:")
pattern1 = '[a-zA-Z0-9]{3,}@163.com' # 精确匹配三次
result1 = re.match(pattern1, str)
if result1 is not None :
    print(result1.group())
else:
    print('邮箱格式错误')
    pass

原生字符串

在大多数编程语言相同,正则表达式里使用“\”作为转义字符,这就可以能 造成反斜 杠困扰。示例如下:

path = 'C:\\a\\b\\c'
print(path)
# 结果 :C:\a\b\c

在python语言之中如果要匹配 '\'

import re
s = 'c:\\a\\b\\c'
# m=re.match('c:\\a\\b',s) #无法匹配到
# 需要 4 个反斜杠“\\\\”:前面两个和后两个分别用于在编程语言里
# 转义成反斜杠,转换成两个反斜杠后再在
# 正则表达式里转义成一个反斜杠

m = re.match('c:\\\\a\\\\b', s)
if m is not None:
    print('匹配的结果 1:', m.group())
else:
    print('无法匹配')
# 结果:
# 匹配的结果 1: c:\a\b

python提供了修饰符'r'表示不需要转义

import re
str = 'c:\\a\\b\\c'
str_r = r'c:\e\f\g\h'
m = re.match('c:\\\\a\\\\b', str)
m2 = re.match(r'c:\\e\\f\\g',str_r)
m3 = re.match(r'c:\\a\\',str)

print(m.group())
print(m2.group())
print(m3.group())

# 结果:
# c:\a\b
# c:\e\f\g
# c:\a\
总结

r的使用是的原本需要写成 \\b \t的匹配规则直接可以写作:r'\b'

边界字符

1、^ $的使用:

  • ^ 表示必须以后面的所有字符开头
import re

str = '12345687@qq.com'
str1 = '1248437598@qq.com'
pattern = '^123\d*@qq.com'
m = re.match(pattern, str)
m1 = re.match(pattern,str1)

print(m.group())
print(m1.group())


# 结果:
# 12345687@qq.com
# Traceback (most recent call last):
#   File "e:/ZOEDestop/bgImg/正则表达式.py", line 10, in <module>
#     print(m1.group())
# AttributeError: 'NoneType' object has no attribute 'group'
  • $表示必须以前面的所有字符结尾
import re

str = '1234567@qq.com'
str1 = '1248_8@qq.com'
pattern = '[^8]*@\w{2,10}.com$' #[^]8所有字符除了8
m = re.match(pattern, str)
m1 = re.match(pattern,str1)

print(m.group())
print(m1.group())
# 1234567@qq.com
# Traceback (most recent call last):
#   File "e:/ZOEDestop/bgImg/正则表达式.py", line 10, in <module>
#     print(m1.group())
# AttributeError: 'NoneType' object has no attribute 'group'

\b \B的使用

\b 匹配一个单词的边界
\B 匹配非单词的边界

  • \b 匹配一个单词的边界
    • XXX\b -- 匹配每个单词必须要以XXX结尾
    • \bxxx -- 匹配的每个单词必须要以xxx开头
import re

# 从右边开始匹配**单词与符号之间**是否满足规则,满足则输出整个字符串
# 不满足则继续匹配下一个下一个边界
# 下面的str1为例:匹配第一个边界为:'yurifgucom weew_com tyuo_com1'的最右边不满足
# 匹配第二个边界为:'yurifgucom weew_com' 满足输出
str = 'yurifgucom weew_com tyuo_com1' 
str1 = '1248_8@qq.com1 erg'
pattern = r'.*com\b'
m = re.match(pattern, str)
m1 = re.match(pattern,str1)

print(m.group())
print(m1.group())

# 结果:
# yurifgucom weew_com
# Traceback (most recent call last):
#   File "e:/ZOEDestop/bgImg/正则表达式.py", line 20, in <module>
#     print(m1.group())
# AttributeError: 'NoneType' object has no attribute 'group'
  • \B = [^\b] 匹配非单词边界(单词与单词、字符与字符之间的边界)也即:每个字母与字母之间符号与符号之间,不包括字母与符号
import re

#\B为非单词边界 单词语单词 符号与符号之间额边界
pattern = r'.*\Bab'
# 类似于\b \B从右边开始匹配第一个非单词边界(下面用**↑**)标识
#  'v↑b↑h↑a↑b a↑b #↑#a↑b↑a↑b#a↑b'
v = re.match(pattern, 'vbhab ab ##abab#ab')
print(v)
# ab 不为右边界
pattern = r'.*ab\B'
v = re.match(pattern, 'wabe')
print(v)
# 结果:
# <re.Match object; span=(0, 15), match='vbhab ab ##abab'>
# <re.Match object; span=(0, 3), match='wab'>

分组匹配

分组匹配的规则:

符号 匹配规则
| 匹配左右任意一个表达式
(ab) 将括号中字符作为一个分组
\num 引用分组num匹配到的字符串
(?P) 分组起别名(必须大写)
(?P=name) 引用别名为name分组匹配到的字符串
  • |的使用
import re

# 匹配出0-199之间的数字
# |前是一个规则,后也是一个规则,在匹配时前面规则不满足才会匹配下一个规则
rex = r'^1\d\d|\d?\d$'
while True:
    match_str = input("输入一个字符串:")
    if match_str == 'no':
        break;
        pass
    print(re.match(rex,match_str))
# 结果:
# 输入一个字符串:456
# None
# 输入一个字符串:45
# <re.Match object; span=(0, 2), match='45'>
# 输入一个字符串:56
# <re.Match object; span=(0, 2), match='56'>
# 输入一个字符串:789
# None
# 输入一个字符串:0 
# <re.Match object; span=(0, 1), match='0'>
# 输入一个字符串:2
# <re.Match object; span=(0, 1), match='2'>
# 输入一个字符串:no
  • () 和 \num 的使用
import re

# 匹配一个html标签
str_html = '<html><br>你好啊</br></html>'
# <(.*)> <>内的内容必须要使用()因为如果不使用后面的\num无法找到
# 对应的匹配的标签 (</\2>)的括号可不写
rex_html = r'<(.*)><(.*)>(.*)(</\2>)(</\1>)'
res = re.match(rex_html, str_html)
print(res)  
# 结果 :<re.Match object; span=(0, 25), 
# match='<html><br>你好啊</br></html>'>
print(res.group(0))  # 结果 : <html><br>你好啊</br></html>
print(res.group(1))  # 结果:html 组一的结果
print(res.group(2))  # 结果 :br 组二的结果
  • (?P<要起的别名>) (?P=起好的别名)
import re

# 匹配一个html标签
# 
str_html = '<html>-<br>你好啊</br>-</html>'
rex_html = r'<(?P<name1>.*)>-<(?P<name2>.*)>.*</(?P=name2)>-</(?P=name1)>'
print(re.match(rex_html, str_html))
# 结果:
# <re.Match object; span=(0, 27), match='<html>-<br>你好啊</br>-</html>'>

re模块的方法

re.compile方法

  • compile将正则表达式模式编译成一个正则表达式对象
    • reg = re.compile(pattern)
      result = reg.match(string)
    • 等效于 result= re.match(pattern, string)
    • 使用 recompile()和保存所产生的正则表达式对象重用效率更高
from  time import * 
# 使用compile一次编译可以使用无数次提高了效率
rexed = re.compile(r'(\d?\d)$')

begin_time = time()
count = 1000000
while count:
    count -= 1
    rexed.match('89')
    pass
end_time = time()
print(end_time - begin_time)

count = 1000000
rex_str = r'(\d?\d)$'
begin_time = time()
while count:
    count -= 1
    re.match(rex_str,'89')
    pass
end_time = time()
print(end_time - begin_time)
# 结果:
# 0.49109530448913574
# 1.1046862602233887

re.search 方法

search 在一个字符串中搜索满足文本模式的字符串。语法格式如下:

re.search(pattern, string, flags=0)

search 函数参数说明:

参数 描述
pattern 匹配的正则表达式
string 要匹配的字符串
flags 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。如下表列出正则表达式修饰符一可选标志,同re.match()
search() 与 match() 类似
search() 会在字符串内寻找可以匹配的且只匹配一次
match() 会在字符串的开头匹配不成功则返回None
import re
print(re.match("you","you are yourself"))
# <re.Match object; span=(0, 3), match='you'>
print(re.match("are","you are yourself"))
# None
print(re.search("you","you are yourself"))
# <re.Match object; span=(0, 3), match='you'>
print(re.search("are","you are yourself"))
# <re.Match object; span=(4, 7), match='are'>

re.findall

在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的, 则返回空列表。语法格式如下:

findall(pattern, string, flags=0)

pattern 匹配的正则表达式
string 要匹配的字符串。
flags 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。如下表列出正则表达式修饰符一可选标志

import re
pattern=r'\w+' 
s='first 1 second 2 third 3 —— _' 
o=re.findall(pattern,s) 
print(o)
# 结果
# ['first', '1', 'second', '2', 'third', '3', '_']

re.finditer

re.finditer 函数 和 findall 类似,在字符串中找到正则表达式所匹配的所有子串,并把它们作为一个迭代器返回。

pattern=r'\w+' 
s='first 1 second 2 third 3 —— _' 
o=re.finditer(pattern,s) 
print(o)
for i in o:
    print(i)
# <callable_iterator object at 0x00000261F2F84E80>
# <re.Match object; span=(0, 5), match='first'>  
# <re.Match object; span=(6, 7), match='1'>      
# <re.Match object; span=(8, 14), match='second'>
# <re.Match object; span=(15, 16), match='2'>    
# <re.Match object; span=(17, 22), match='third'>
# <re.Match object; span=(23, 24), match='3'>
# <re.Match object; span=(28, 29), match='_'>

splite函数

re.split(pattern, string[, maxsplit=0, flags=0])

参数 描述
pattern 匹配的正则表达式
string 要匹配的字符串。
maxsplit 分隔次数, maxsplit=1分隔一次,默认为0,不限制次数。
flags 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
import re

s='first 11 second 22 third 33' #按数字切分 
print(re.split(r'\d+',s)) # maxsplit 参数限定分隔的次数,这里限定为 1,也就是只分隔一次 
print(re.split(r'\d+',s,1))
# 结果:
# ['first ', ' second ', ' third ', '']
# ['first ', ' second 22 third 33']

re.sub 和 re.subn搜索与替换

sub 函数和 subn 函数用于实现搜索和替换功能。这两个函数的功能几乎完全相同,都是将某个字符串中所有匹配正则表达式的部分替换成其他字符串。

sub 函数返回替换后的结果,
subn 函数返回一个元组,元组的第 1 个元素是替换后的结果,第 2 个元素是替换的总数。

语法为:

re.sub(pattern, repl, string, count=0, flags=0)

参数 描述
pattern 匹配的正则表达式
repl 替换的字符串,也可为一个函数
string 要被查找替换的原始字符串。
count 模式匹配后替换的最大次数,默认0表示替换所有的匹配
import re

phone = "哎呀喂 2004-959-559 # 这是一个国外电话号码" # 删除字符串中的 Python 注释 
# 第一个参数是中文的范围
rex = '[\u4e00-\u9fa5]|#'
# sub返回替换结果 0 代表无穷个
str = re.sub(rex,"",phone,0)
print(str)

# 使用subn
rex_compiled = re.compile(r'[\u4e00-\u9fa5]|#')
result = rex_compiled.subn("",phone,0)
# 替换结果
print(result[0])
# 替换个数
print(result[1])

贪婪模式和非贪婪模式

Python里数量词默认是贪婪的,总是尝试匹配尽可能多的字符,非贪婪则相反,总是尝试匹配尽可能少的字符。
在"*","?"+";"{m,n}"后面加上?,使贪婪变成非贪婪。

import re

test = 'acbacbabbb'
# 非贪婪模式
rex = re.compile('a.*?b')
print(rex.search(test)) # <re.Match object; span=(0, 3), match='acb'>

#贪婪模式
rex = re.compile('a.*b')
print(rex.search(test))# <re.Match object; span=(0, 10), match='acbacbabbb'>
posted @ 2021-04-12 17:37  zoewhence  阅读(132)  评论(0)    收藏  举报