前言
问:正则表达式 为何物?
简单来说,正则表达式 就是一套用于描述字符串排列的规则。通过正则表达式可以在任意的字符串中匹配出需要的结果。
在python语言中,通过调用 RE 模块 来实现正则表达式的使用。同时,其 re 也是一种小型、高度专业化的编程语言。
功能及原理:通过一些特定的字符组合成一条正则表达式,然后程序根据用户的设定,将其匹配到的内容(字符串)返回;反之,则不返回任何字符串(即过滤)。
正则表达式组成?
正则表达式大致由:原子、元字符、模式修正符和一些其它符号组成。
原子
原子是正则表达式中最基本的组成单位,每个正则表达式中至少要包含一个原子,常见的原子及其组合有以下几类:
- 普通字符作为原子
- 非打印字符作为原子
- 通用字符作为原子
- 原子表
(1)普通字符作为原子
使用普通字符作为原子,如:数字、大小写字母、下划线等。
例如:使用普通字符串"tai"作为原子使用,其组合就一共有 3 个小原子,即 t
、a
、i
。
实例演示:
从指定字符串中匹配与"tai"相关的字符集。
import re
pattern = "tai"
string = "http://www.taitaiblog.com"
result = re.search(pattern, string)
print(result)
实例输出:
<_sre.SRE_Match object; span=(11, 14), match='tai'>
分析:第一行中,我们首先引入了正则表达式需要的 re 模块,第二行定义了一个普通的原子"tai"并将其赋值给 pattern变量,第三行设定一个需要待匹配的字符串,第四行则调用 re 模块中的 search()函数,通过该函数从string中匹配对应的正则表达式,有其值则返回对应的值,并赋给result变量,最终显示出来。
从输出结果可见,最终输出的是一个对象,并非实际匹配到的字符串,然而这并不影响,后面我们会讲如何通过对象取其中匹配到的值。
(2)非打印字符作为原子
所谓的非打印字符,指的是在编程中一些用于控制格式的符号。常见的,如:换行符 \n
、制表符 \t
等等
实例演示:
import re
pattern = "\n"
string1 = """www.taitaiblog.com
www.csdn.net""" # 有换行
string2 = "www.taitaiblog.comwww.csdn.net" # 无换行
result1 = re.search(pattern, string1) # 匹配 有换行 的字符串
result2 = re.search(pattern, string2) # 匹配 无换行 的字符串
print(result1)
print(result2)
实例输出:
<_sre.SRE_Match object; span=(18, 19), match='\n'>
None
分析:从实例可以看出,定义"\n"非打印字符正则,可以迅速知道某个源字符串中是否含有对应的特殊字符。
(3)通用字符作为原子
所谓的通用字符 ,指的是使用一个原子可以匹配某一类的字符集的特殊字符,常见的通用字符及其含义如下表:
符号 | 含义 |
---|---|
\w | 匹配任意一个字母、数字或下划线 |
\W | 匹配除字符、数字和下划线以外的任意一个字符 |
\d | 匹配任意一个十进制数 |
\D | 匹配除十进制数以外的任意一个其它字符 |
\s | 匹配任意一个空白字符 |
\S | 匹配除空白字符以外的任意一个其它字符 |
实例演示:
import re
pattern = "\wpython\d\w" # 定义通用字符正则
string1 = "ABCpython3_abc" # 情况一
string2 = "123python2ABC" # 情况二
result1 = re.search(pattern, string1)
result2 = re.search(pattern, string2)
print(result1)
print(result2)
实例输出:
<sre.SREMatch object; span=(2, 11), match='Cpython3* '>
<* sre.SRE_Match object; span=(2, 11), match='3python2A'>
分析:正则中除了定义普通字python符外,还加入了3个通用字符,作为组合正则,从输出结果可知程序均匹配到了相应的内容,具体的内容为 match 中的值。
(4)原子表
在python中,原子表用 [] 表示,其功能是:定义一组地位平等的原子。在匹配正则时,会自动的抽取其中的原子进行比对。如果正则中除了原子表 还有其它的原子 ,程序会自动的抽取原子表中的任一原子,并将其放到合适的位置,组合后再进行比对。
原子表匹配有两种情况:
(1)匹配原子表中含有对应字符的内容(即包含原子表内的元素)
(2)匹配除原子表中含有字符以外的内容(即不包括原子表内的元素)
匹配原子表中包含的元素
例如:定义正则 pattern = "[ABC]python",其最终可以匹配出以下可能结果:"Apython"、"Bpython"、"Cpython".
实例如下:
import re
pattern = "[ABC]python\d\w"
string1 = "Bpython3study" # 匹配1
string2 = "Apython2learn" # 匹配2
string3 = "Bpython3studyApython2learn" # 匹配3-测试匹配优先顺序
string4 = "Dpython3study" # 不匹配1
result1 = re.search(pattern, string1)
result2 = re.search(pattern, string2)
result3 = re.search(pattern, string3)
result4 = re.search(pattern, string4)
print(result1)
print(result2)
print(result3)
print(result4)
实例输出:
<*sre.SRE_Match object; span=(0, 9), match='Bpython3s'>
<* sre.SRE_Match object; span=(0, 9), match='Apython2l'>
<_sre.SRE_Match object; span=(0, 9), match='Bpython3s'>
None
分析:这里只分析 “匹配3” 的过程,在 pattern 中,定义的是 [ABC],其顺序是 "A" → "B" → "C",而在源字符串 string3 中,定义的两个内容均是匹配的,只是有先后顺序,"Bpython3study" 在前,"Apython2learn" 在后,而从输出结果第三行中可见首先匹配到的却是 "Bpython3study" ,其主要原因是 re 在匹配时,会优先的匹配目标字符串中首个合适的内容,并非根据原子表中原子出现的顺序进行匹配。说白了,就是要在目标字符串中找到第一个合适的内容。
元字符
元字符,指的是正则表达式中一些具有特殊含义的字符。比如某一元字符可以重复N 次前面的字符等。
常见的元字符及其含义如下:
符号 | 含义 |
---|---|
. | 匹配除换行以外的任意字符 |
^ | 匹配字符串的开始位置 |
$ | 匹配字符串的结束位置 |
* | 匹配0次、1次或多次前面的原子 |
? | 匹配0次或1次前面的原子 |
+ | 匹配1次或多次前面的原子 |
{n} | 前面的原子恰好出现n次 |
{n,} | 前面的原子至少出现n次 |
{n,m} | 前面的原子至少出现n次,至多出现m次 |
() | 模式单元符 |
(1)任意匹配元字符
在众多的元字符中,可以使用“.”元字符来匹配一个除换行以外的任意字符。
实例如下:
import re
pattern = ".python..tudy"
string = "Apython3study"
result = re.search(pattern, string)
print(result)
实例输出:
<_sre.SRE_Match object; span=(0, 13), match='Apython3study'>
分析:可见一个元字符"."可以代替一个任意的字符!
(2)边界限制元字符
边界限制元字符有两个,分别为: ^
和 $
。
^
元字符:用于匹配字符串的开始。$
元字符:用于匹配字符串的结束。
实例如下:
import re
# 行首匹配( ^ )
pattern1 = "^abc"
pattern2 = "^abd"
# 行末匹配( $ )
pattern3 = "dy$"
pattern4 = "ey$"
string = "abc_python_study"
result1 = re.search(pattern1, string)
result2 = re.search(pattern2, string)
result3 = re.search(pattern3, string)
result4 = re.search(pattern4, string)
print(result1)
print(result2)
print(result3)
print(result4)
实例输出:
<*sre.SRE_Match object; span=(0, 3), match='abc'>
None
<* sre.SRE_Match object; span=(14, 16), match='dy'>
None
分析:(略)
注意:使用该元字符时,注意元字符的定义位置,^
应在字符的前面,$
应在字符的后面。
(3)次数限定符
常见的次数限定符有:*
、?
、+
、{n}
、{n,}
、{n,m}
这几个,具体含义,参照上表即可!
各实例如下:
*
匹配前面原子出现 0 次或以上次数 元字符
import re
pattern = "hello*" # 出现0次或以上次数
string1 = "hel" # 不匹配
string2 = "hell" # 匹配
string3 = "hello"
string4 = "hellooooo"
print(re.search(pattern, string1))
print(re.search(pattern, string2))
print(re.search(pattern, string3))
print(re.search(pattern, string4))
实例输出:
None
<*sre.SRE_Match object; span=(0, 4), match='hell'>
<* sre.SRE_Match object; span=(0, 5), match='hello'>
<_sre.SRE_Match object; span=(0, 9), match='hellooooo'>
?
指定前面原子可有可无状态 元字符
import re
pattern = "ab?c" # 指定 b 可有可无状态
string1 = "ac" # 匹配
string2 = "abc"
string3 = "abbc" # 不匹配
print(re.search(pattern, string1))
print(re.search(pattern, string2))
print(re.search(pattern, string3))
实例输出:
<*sre.SRE_Match object; span=(0, 2), match='ac'>
<* sre.SRE_Match object; span=(0, 3), match='abc'>
None
+
匹配前面原子出现1次或以上次数 元字符
import re
pattern = "hello+" # 指定 o 必须出现1次或以上次数
string1 = "hell" # 不匹配
string2 = "hello" # 匹配
string3 = "hellooo"
print(re.search(pattern, string1))
print(re.search(pattern, string2))
print(re.search(pattern, string3))
实例输出:
None
<*sre.SRE_Match object; span=(0, 5), match='hello'>
<* sre.SRE_Match object; span=(0, 7), match='hellooo'>
{n}
、{n, }
、{n,m}
匹配自定义前面原子出现次数 元字符
import re
pattern1 = "ab{2}" # 匹配 b 出现两次的字符
pattern2 = "ab{2,}" # 匹配 b 出现2次或以上次数的字符
pattern3 = "ab{2,6}cd" # 匹配 b 出现2到6次之间的字符
string = "abbbbbbcd"
print(re.search(pattern1, string))
print(re.search(pattern2, string))
print(re.search(pattern3, string))
实例输出:
<*sre.SRE_Match object; span=(0, 3), match='abb'>
<* sre.SRE_Match object; span=(0, 7), match='abbbbbb'>
<_sre.SRE_Match object; span=(0, 9), match='abbbbbbcd'>
分析:(略)
(4)模式选择符
模式选择符 |
与关系运算符 or
类似,即从多个选项中任意匹配其中一个。
import re
pattern = "python|java"
string = "abcjavalearnpython"
print(re.search(pattern, string))
实例输出:
<_sre.SRE_Match object; span=(3, 7), match='java'>
分析:可见优先匹配了字符串 string 中的 java 字符。
(5)模式单元符
模式单元符 ()
,主要功能是将 ()
符内的原子组合成一个大的原子来使用,实例如下:
import re
pattern1 = "(bc)+" # "bc" 组合出现 1次或以上次数
pattern2 = "bc+" # c 字符出现1次或以上次数
string = "abcbcbcbclearnpython"
print(re.search(pattern1, string))
print(re.search(pattern2, string))
实例输出:
<*sre.SRE_Match object; span=(1, 9), match='bcbcbcbc'>
<* sre.SRE_Match object; span=(1, 3), match='bc'>
分析:pattern1 以字符 bc 作为一个新的、单独的原子使用,而 pattern2 则是以字符 b 作为原子,所以程序最终如上输出。
贪婪模式与懒惰模式
在匹配过程中,有 贪婪模式 和 懒惰模式 之分:
- 贪婪模式:其宗旨是尽可能的多地匹配。
- 懒惰模式:其宗旨则是尽可能少地匹配。
实例如下:
import re
pattern1 = "p.*n" # 贪婪模式
pattern2 = "p.*?n" # 懒惰模式
string = "ABCpython2DEFpython3GHIpython4567"
result1 = re.search(pattern1, string)
result2 = re.search(pattern2, string)
print(result1)
print(result2)
实例输出:
<*sre.SRE_Match object; span=(3, 29), match='python2DEFpython3GHIpython'>
<* sre.SRE_Match object; span=(3, 9), match='python'>
分析:可见贪婪模式是尽可能的去匹配更多的内容,而懒惰模式则是尽可能少的去匹配内容(即就近原则)。
问:如何快速设置贪婪模式或懒惰模式?
答:贪婪模式直接使用
.*
符号组合即可,而懒惰模式使用.*?
组合进行设置。
模式修正符
模式修正符,其宗旨是指在不改变事先定义好的正则表达式、不改变元字符的前提下,让其可以兼容一些其它含义上的结果匹配。即通过模式修正符可以对原正则表达式做出一些微小的功能调整。如:加入模式修正符 I
,可以让表达式在匹配时不区分字母的大小写。
常见的模式修正符及其含义:
符号 | 含义 |
---|---|
I | 匹配时忽略字母大小写 |
M | 多行匹配 |
L | 做本地化识别匹配 |
U | 根据Unicode字符及解析字符 |
S | 使元字符"."匹配包括换行在内的所有字符 |
X | 使存在分行符的正则表达式,也能正确匹配(目的:让表达式逻辑更清晰) |
实例如下:
import re
pattern = "python" # 定义正则 1
string1 = "abcPythonStudy" # "P" 为大写
string2 = """
hello world
study python
hello make
study java
hello python
learn end
"""
# 测试忽略大小写匹配
result1 = re.search(pattern, string1, re.I) # 加入"re.I"参数
# 测试 多行匹配
result2 = re.search(pattern, string2, re.M) # 加入 "re.M"参数
# 测试 元字符"."匹配包括换行在内的所有字符
pattern2 = "(python).+(python)"
result3 = re.search(pattern2, string2, re.S)
print(result1)
print(result2)
print(result3)
实例输出:
<*sre.SRE_Match object; span=(3, 9), match='Python'>
<*sre.SRE_Match object; span=(19, 25), match='python'>
<_sre.SRE_Match object; span=(19, 60), match='python\nhello make\nstudy java\nhello python'>
分析:(略)
完整学习教程请访问 :Python3 入门教程——目录索引