目录
我们在进行字符串处理的时候,希望按自定义的规则进行处理,我们将这些规则称为模式。我们使用正则表达式来表示这些规则。
一、什么是正则表达式
正则表达式就是表述字符排列的一套规则,它的功能非常强大,在实际项目中,但主要是用来处理某种特定格式的信息。
在python中,我们主要使用re模块来实现python的正则表达式功能。
二、正则表达式的基础知识
本节主要讲述正则表示如何去写,我们将分别从原子、元字符、模式修改、贪婪模式和懒惰模式等方面进行介绍。关于正则表达式的使用则在下一小节中详细介绍。
1. 原子
原子是正则表达式中的基本组成单元,每一个正则表达式中至少包含一个原子,常见的原子种类有以下几种:
- 普通字符作为原子。
- 非打印字符作为原子。
- 通用字符作为原子。
- 原子表。
接下来我们分别对这几类进行详细介绍。
1)普通字符作为原子
普通字符主要指得是字母、数据、下划线。
我们可以使用普通字符组成的正则表达式去查找相应的字符。例如我们的正则表达式为”python”,然后去字符串string中去寻找是否包含符合正则表达式的字符串(“python“):
import re
pattern = "assd"
string = "C:\\Users\\root\\AppData\\Local\\Programs\\Python\\Python37-32" \
"\\python.exe D:\\pycharm\\workspace\\spiderAnalysis\\AI_pie\\main.py"
result = re.search(pattern, string)
print(result)
<re.Match object; span=(56, 62), match='python'>
or
None
2)非打印字符作为原子
非打印字符主要指的是字符串中的控制字符,例如换行符,空格,tab等。
表2.1列出了几个常见的非打印字符及其含义
表2.1 非打印字符表 |
|||
序号 |
符号 |
含义 |
|
1 |
\n |
用于匹配一个换行符 |
|
2 |
\t |
用于匹配一个制表符 |
|
3 |
Pycharm中,如果想通过回车实现换行的话,实际在字符串中是没有换行符”\n”的,因为它是通过拼接实现的,自动把换行符给去掉了。
pattern = '\n'
string = "C:\\Users\\root\\AppData\\Local\nPrograms\\Python\\Python37-32" \
"\\python.exe D:\\pycharm\\workspace\\spiderAnalysis\\AI_pie\\main.py"
result = re.search(pattern, string)
#print(string)
#print(result)
'''
C:\\Users\root\AppData\Local
Programs\Python\Python37-32\python.exe D:\pycharm\workspace\spiderAnalysis\AI_pie\main.py
<re.Match object; span=(27, 28), match='\n'>
'''
3) 通用字符作为原子
接下来介绍通用字符。
所谓通用字符指的是,一个原子可以匹配一类字符。
这在实际项目中非常有用。常见的通用字符及其含义如下表:
表2.2 常见的通用字符及其含义 |
|||
序号 |
符号 |
含义 |
|
1 |
\w |
匹配任意一个字母、数字、下划线 |
|
2 |
\W |
匹配除了字符数字下划线的其他一个字符 |
|
3 |
\d |
匹配一个十进制数字 |
|
4 |
\D |
匹配除了十进制数字以外的其他字符 |
|
5 |
\s |
匹配一个空格 |
|
6 |
\S |
匹配一个除了空格以外的其他字符 |
|
4) 原子表
使用原子表来定义一组地位平等的原子,然后匹配的时候会去该原子表的任意一个原子进行匹配,在python中,原子表示用[]来表示。
如[xyz]就是一个原子表,这里面的三个原子’x’,’y’,’z’的的地位完全一致。
pattern1 = "\w\dpython\d[xyz]\w"
pattern2 = "\w\dpython\d[^xyz]\w"
pattern3 = "\w\dpython\d[xyz]\W"
string = "pycharm\a2a222python6\\a2adeepython6\\a2python6xyz\main.py"
print(re.search(pattern1, string))
print(re.search(pattern2, string))
print(re.search(pattern3, string))
'''
<re.Match object; span=(35, 46), match='a2python6xy'>
<re.Match object; span=(11, 22), match='22python6\\a'>
None
'''
原子表的另一种常用的是匹配除了该表中的其他任意一个字符:[^]。例如[^x“[^xyz]py”能匹配”apy”, 无法匹配”xpy”。
2. 元字符
介绍完毕原子的使用,接下来介绍下元字符的使用。
所谓的元字符,指的是在正则表达式中具有的一些特殊含义的字符。比如恰前面重复N次的字符,这些使用原子是很不容易操作的。元字符可以分为任意匹配元字符、边界限制元字符、限定符、模式选择符、模式单元符。
下面是整理的一些常见元字符:
表2.3 常见的元字符及其含义 |
|||||
序号 |
符号 |
含义 |
|||
1 |
. |
匹配出换行符之外的任意字符 |
|||
2 |
^ |
匹配字符串的开始 |
|||
3 |
$ |
匹配字符串的结尾 |
|||
4 |
* |
匹配0次,1次,多次前面的原子 |
|||
5 |
? |
匹配0次或1次前面的原子 |
|||
6 |
+ |
匹配一次或多次前面的原子 |
|||
7 |
{m} |
前面的原子恰好出现m次 |
|||
8 |
{m,} |
前面的原子最少出现m次 |
|||
9 |
{m,n} |
前面的原子至少出现m次,最多n次 |
|||
10 |
| |
模式选择符 |
|||
11 |
() |
模式单元符 |
1)任意匹配元字符
首先介绍任意匹配元字符“.”, 我们可以使用它来匹配除了换行符以外的其他任意字符。例如我们可以使用“. python . . .” 来匹配一个“python”字符前面有1位,后面有3位除了换行符以外的其他任意字符:“apython123”, “1pythonxxx”, “2python333”等等。
pattern1 = "..python..."
string = "pycharm\a2a222python6\\a2adeepython6\\a2python6xyz\main.py"
#print(re.search(pattern1, string))
'''
<re.Match object; span=(11, 22), match='22python6\\a'>
'''
2)边界限制元字符
接下来我们介绍边界限制元字符。我们使用‘^’来匹配一个字符串的开始,使用“$”来匹配字符串的结尾。eg:
pattern1 = "^hello"
pattern2 = "^hellp"
pattern3 = "python$"
pattern4 = "pthon$"
string = "hello, good morning python"
#print(re.search(pattern1, string))
#print(re.search(pattern2, string))
#print(re.search(pattern3, string))
#print(re.search(pattern4, string))
'''
<re.Match object; span=(0, 5), match='hello'>
None
<re.Match object; span=(20, 26), match='python'>
None
'''
3)限定符
限定符主要包括:*,+,?,{m},{m,},{m,n}。
“py.*”: 匹配“py”开头的除了换行符的任意长度的字符串。例如
pattern1 = "py.*"
pattern2 = "cd{2}"
pattern3 = "(cd){3,}"
pattern4 = "cd{3,5}"
string = "apycdcdcdcdddddaaaaaaaaaaaaaaaaaaa.a\nbb"
print(re.search(pattern1, string))
print(re.search(pattern2, string))
print(re.search(pattern3, string))
print(re.search(pattern4, string))
'''
<re.Match object; span=(1, 36), match='pycdcdcdcdddddaaaaaaaaaaaaaaaaaaa.a'>
<re.Match object; span=(9, 12), match='cdd'>
<re.Match object; span=(3, 11), match='cdcdcdcd'>
<re.Match object; span=(9, 15), match='cddddd'>
'''
4)模式选择符
接下来介绍模式选择符“|”。我们可以使用“|”来设置多个模式,使用的时候可以从中选择任意一个模式进行匹配。比如正则表达式”python|php”则既可以匹配“python”也可以匹配”php”。eg:
pattern = "python|php"
string1 = "dseklkjlcphpadepythonsadenkcken,mx"
string2 = "dseklkjlcpnpadepythonsadenkcken,mx"
print(re.search(pattern, string1))
print(re.search(pattern, string2))
'''
<re.Match object; span=(9, 12), match='php'>
<re.Match object; span=(15, 21), match='python'>
'''
5)模式单元符
模式单元符指的是”()”,我们可以“()”将一组原子组合成一个大原子,使用小括号括起来将他们作为一个整体进行处理。
pattern1 = "(cd){3,}"
pattern2 = "cd{3}"
string1 = "cdcdcdcdcdcdcdcdcdcd"
string2 = "ccccccccccccdddddddddd"
print(re.search(pattern1, string1))
print(re.search(pattern2, string1))
print(re.search(pattern1, string2))
print(re.search(pattern2, string2))
'''
<re.Match object; span=(0, 20), match='cdcdcdcdcdcdcdcdcdcd'>
None
None
<re.Match object; span=(11, 15), match='cddd'>
'''
3. 模式修正
上面我们介绍完了一些常用元字符的使用情况,下面我们讲解模式修改符。所谓的模式修正符指的是在不改变正则表达式的情况下,通过修改模式修正符来改变正则表达式的含义,从而实现一些匹配结果的调整功能。比如我们可以使用模式修正符“I“来忽略大小写。
一些常见的模式修正符如下:
表2.4模式修正符 |
|||
序号 |
符号 |
含义 |
|
1 |
I |
匹配是忽略大小写 |
|
2 |
M |
多行匹配 |
|
3 |
L |
做本地化识别匹配 |
|
4 |
U |
根据unicode字符及解析字符 |
|
5 |
S |
让‘.’可以匹配任意字符 |
|
eg:
pattern = "python"
string = "oienchemkfhhanciefnmnasdffaeinpych\n" \
"armworkspacespiderAnalysisPytoncaPYTHON;"
#print(re.search(pattern, string))
#print(re.search(pattern, string, re.I | re.M))
'''
None
<re.Match object; span=(68, 74), match='PYTHON'>
'''
4. 懒惰模式和贪婪模式
贪婪模式的特点是尽可能多的去匹配;懒惰模式的特点是尽可能少的去匹配。
我们举个栗子来间的说明下这两种模式:
pattern1 = "p.*y" #贪婪模式
pattern2 = "p.*?y" #懒惰模式
string = "pysldjefiejcnesdffasdfasdfasdfasdfasdfbbbbbbbbasdffeceadfyyyyyyyybbbbbbbbbbbdeceadfebbbbbbbbbbby"
print(string.__len__())
print(re.search(pattern1, string).span()) #匹配的结果长的话显示不全,因而显示出下标范围
print(re.search(pattern2, string))
通常情况下,如果我们想在某些字符间匹配任意字符,像 “p.*y“ 这样采用的便是贪婪模式,如果想要转化为懒惰模式,则使用 ”p.*?y“ 便可以转换为懒惰模式。
三、正则表达式常见的函数
上节已经介绍完了一些基本的正则表达式的知识,但是这些正则表达式需要和正则表达式函数进行配合才能完成相关的功能。
我们常用的正则表达式函数有re.match(), re.search(), 全局搜索函数, re.sub()等函数。下面我们一一来介绍。
1. re.match()
如果想要从源字符串的起始位置匹配一个模式,我们可以使用re.match()函数来完成。
re.match()的函数格式为:
表3.1 re.match()函数简介 |
||
re.match(pattern, string, flag) |
||
pattern |
正则表达式 |
|
string |
带匹配的源字符串 |
|
flag |
模式修正符 |
2. re.search()
re.search()函数跟match()函数最大的区别在于search()函数在全文中进行检索并匹配。而match()函数则是在源字符串的开头进行匹配。
表3.2 re.search()函数简介 |
||
re.search(pattern, string, flag) |
||
pattern |
正则表达式 |
|
string |
带匹配的源字符串 |
|
flag |
模式修正符 |
3. 全局匹配函数
通过在讲解正则表达式的基本规则的时候可以发现,在上述匹配过程中,即使有多个结果符合模式,也只会匹配一个结果,那么怎样才可以将所有满足要求的内容全部匹配出来呢?
思路如下:
1) 使用re.compile()对正则表达式进行预编译
2)编译后,使用findall根据正则表达式从源字符串里将匹配的结果全部找出。
表3.2 全局匹配功能简介 |
||
re.compile(pattern).findall(string) |
||
pattern |
正则表达式 |
|
string |
带匹配的源字符串 |
'''
5. 全局匹配函数
'''
string = "ecnepythonaskdjllelpythondkljec,pythonmkjklpythondsecml"
result = re.compile(".python..").findall(string)
print(result)
'''
['epythonas', 'lpythondk', ',pythonmk', 'lpythonds']
'''
4. re.sub()
如果想要根据正则表达式来实现替换源字符串的某些字符串我们可以使用re.sub()来实现, 该函数也是全局寻找并根据设置的max值来决定替换的次数。re.sub()函数格式如下:
表3.4 re.sub()函数简介 |
||
re.sub(pattern, rep, string, max) |
||
pattern |
正则表达式 |
|
rep |
要替换成的字符串 |
|
string |
带匹配的源字符串 |
|
max |
最多匹配的次数 |
'''
6. re.sub函数
'''
string = "ecnepythonaskdjllelpythondkljec,pythonmkjklpythondsecml"
pattern = ".python."
rep = "-PHP-"
result = re.sub(pattern, rep, string, 5)
print(result)
'''
ecn-PHP-skdjlle-PHP-kljec-PHP-kjk-PHP-secml
'''
关于python中yong的正则表达式基本知识、常见用法已经记录完毕。后续如果再实际开发中遇到问题在做记录。