正则表达式 小甲鱼.docx
- 文档编号:16779355
- 上传时间:2023-07-17
- 格式:DOCX
- 页数:13
- 大小:20.99KB
正则表达式 小甲鱼.docx
《正则表达式 小甲鱼.docx》由会员分享,可在线阅读,更多相关《正则表达式 小甲鱼.docx(13页珍藏版)》请在冰点文库上搜索。
正则表达式小甲鱼
正则表达式介绍
(一)
正则表达式(Regularexpressions也称为REs,或regexes或regexpatterns)本质上是一个微小的且高度专业化的编程语言。
它被嵌入到Python中,并通过re模块提供给程序猿使用。
使用正则表达式,你需要指定一些规则来描述那些你希望匹配的字符串集合。
这些字符串集合可能包含英语句子、e-mail地址、TeX命令,或任何你想要的东东。
正则表达式模式被编译成一系列的字节码,然后由一个C语言写的匹配引擎所执行。
对于高级的使用,你可能需要更关注匹配引擎是如何执行给定的RE,并通过一定的方式来编写RE,以便产生一个可以运行得更快的字节码。
本文暂不讲解优化的细节,因为这需要你对匹配引擎的内部机制有一个很好的理解。
但本文的例子均是符合标准的正则表达式语法。
小甲鱼注释:
Python的正则表达式引擎是用C语言写的,所以效率是极高的。
另,所谓的正则表达式,这里说的RE,就是上文我们提到的“一些规则”。
正则表达式语言相对较小,并且受到限制,所以不是所有可能的字符串处理任务都可以使用正则表达式来完成。
还有一些特殊的任务,可以使用正则表达式来完成,但是表达式会因此而变得非常复杂。
在这种情况下,你可能通过自己编写Python代码来处理会更好些;尽管Python代码比一个精巧的正则表达式执行起来会慢一些,但可能会更容易理解。
小甲鱼注释:
这可能是大家常说的“丑话说在前”吧,大家别管他,正则表达式非常优秀,她可以处理你98.3%的文本任务,一定要好好学哦~~~~~
简单的模式
我们将从最简单的正则表达式学习开始。
由于正则表达式常用于操作字符串的,因此我们从最常见的任务下手:
字符匹配。
字符匹配
大多数字母和字符会匹配它们自身。
举个例子,正则表达式 FishC 将完全匹配字符串 "FishC"。
(你可以启用不区分大小写模式,这将使得 FishC 可以匹配 "FISHC" 或 "fishc",我们会在后边讨论这个话题。
)
当然这个规则也有例外。
有少数特殊的字符我们称之为元字符(metacharacter),它们并不能匹配自身,它们定义了字符类、子组匹配和模式重复次数等。
本文用很大的篇幅专门讨论了各种元字符及其作用。
下边是元字符的完整列表(我们将在后边逐一讲解):
. ^ $ * + ?
{} [] | ()
小甲鱼注释:
如果没有这些元字符,正则表达式就变得跟字符串的find()方法一样平庸了......
我们先来看下方括号 [],它们指定一个字符类用于存放你需要匹配的字符集合。
可以单独列出需要匹配的字符,也可以通过两个字符和一个横杆 - 指定匹配的范围。
例如 [abc] 会匹配字符 a,b 或 c;[a-c] 可以实现相同的功能。
后者使用范围来表示与前者相同的字符集合。
如果你想只匹配小写字母,你的RE可以写成 [a-z]。
需要注意的一点是:
元字符在方括号中不会触发“特殊功能”,在字符类中,它们只匹配自身。
例如 [akm$] 会匹配任何字符 'a','k','m' 或 '$','$' 是一个元字符,但在方括号中它不表示特殊含义,它只匹配 '$' 字符本身。
你还可以匹配方括号中未列出的所有其他字符。
做法是在类的开头添加一个脱字符号 ^ ,例如 [^5] 会匹配除了 '5' 之外的任何字符。
或许最重要的元字符当属反斜杠 了。
跟Python的字符串规则一样,如果在反斜杠后边紧跟着一个元字符,那么元字符的“特殊功能”也不会被触发。
例如你需要匹配符号 [ 或 ,你可以在它们前面加上一个反斜杠,以消除它们的特殊功能:
[,\。
反斜杠后边跟一些字符还可以表示特殊的意义,例如表示十进制数字,表示所有的字母或者表示非空白的字符集合。
小甲鱼解释:
反斜杠真牛逼,反斜杠后边跟元字符去除特殊功能,反斜杠后边跟普通字符实现特殊功能。
让我们来举个例子:
w 匹配任何字符。
如果正则表达式以字节的形式表示,这相当于字符类 [a-zA-Z0-9_];如果正则表达式是一个字符串,w 会匹配所有Unicode数据库(unicodedata模块提供)中标记为字母的字符。
你可以在编译正则表达式的时候,通过提供re.ASCII表示进一步限制 w 的定义。
小甲鱼解释:
re.ASCII标志使得w只能匹配ASCII字符,不要忘了,Python3是Unicode的。
下边列举一些反斜杠加字符构成的特殊含义:
特殊字符
含义
d
匹配任何十进制数字;相当于类 [0-9]
D
与 d 相反,匹配任何非十进制数字的字符;相当于类 [^0-9]
s
匹配任何空白字符(包含空格、换行符、制表符等);相当于类 [tnrfv]
S
与 s 相反,匹配任何非空白字符;相当于类 [^tnrfv]
w
匹配任何字符,见上方解释
W
于 w 相反
b
匹配单词的开始或结束
B
与 b 相反
它们可以包含在一个字符类中,并且一样拥有特殊含义。
例如 [s,.] 是一个字符类,它将匹配任何空白字符(/s 的特殊含义),',' 或 '.'。
最后我们要讲的一个元字符是 .,它匹配除了换行符以外的任何字符。
如果设置了re.DOTALL标志,. 将匹配包括换行符在内的任何字符。
重复的事情
使用正则表达式能够轻松的匹配不同的字符集合,但Python字符串现有的方法却无法实现。
然而,如果你认为这是正则表达式的唯一优势,那你就tooyoungtoonative了。
正则表达式有另一个强大的功能,就是你可以指定RE部分被重复的次数。
我们来看看 * 这个元字符,当然它不是匹配 '*' 字符本身(我们说过元字符都是有特殊能力的),它用于指定前一个字符匹配零次或者多次。
例如 ca*t 将匹配 ct(0个字符a),cat(1个字符a),caaat(3个字符a),等等。
需要注意的是,由于受到C语言的int类型大小的内部限制,正则表达式引擎会限制字符'a'的重复个数不超过20亿个;不过,通常我们工作中也用不到那么大的数据。
正则表达式默认的重复规则是贪婪的,当你重复匹配一个RE时,匹配引擎会尝试尽可能多的去匹配。
直到RE不匹配或者到了结尾,匹配引擎就会回退一个字符,然后再继续尝试匹配。
我们通过例子一步步的给大家讲解什么叫“贪婪”:
先考虑一下表达式 a[bcd]*b,首先需要匹配字符 'a',然后是零个到多个 [bcd],最后以 'b' 结尾。
那现在想象一下,这个RE匹配字符串 abcbd 会怎样?
步骤
匹配
说明
1
a
匹配RE的第一个字符 'a'
2
abcbd
引擎在符合规则的情况下尽可能地匹配 [bcd]*,直到该字符串的结尾
3
失败
引擎尝试匹配RE最后一个字符 'b',但当前位置已经是字符串的结尾,所以失败告终
4
abcb
回退,所以 [bcd]* 匹配少一个字符
5
失败
再一次尝试匹配RE最后一个字符 'b',但字符串最后一个字符是 'd',所以失败告终
6
abc
再次回退,所以 [bcd]* 这次只匹配 'bc'
7
abcb
再一次尝试匹配字符 'b',这一次字符串当前位置指向的字符正好是 'b',匹配成功
最终,RE匹配的结果是 abcb。
小甲鱼解释:
正则表达式默认的匹配规则是贪婪的,后边有教你如何使用非贪婪的方法匹配。
另一个实现重复的元字符是 +,用于指定前一个字符匹配一次或者多次。
要特别注意 * 和 + 的区别:
* 匹配的是零次或者多次,所以被重复的内容可能压根儿不会出现;+ 至少需要出现一次。
例如 ca+t 会匹配 cat 和 caaat,但不会匹配 ct。
还有两个表示重复的元字符,其中一个是问号 ?
,用于指定前一个字符匹配零次或者一次。
你可以这么想,它的作用就是把某种东西标志位可选的。
例如 小?
甲鱼 可以匹配 小甲鱼,也可以匹配 甲鱼。
最灵活的应该是元字符 {m,n}(m和n都是十进制整数),上边讲到的几个元字符都可以使用它来表达,它的含义是前一个字符必须匹配m次到n次之间。
例如 a/{1,3}b 会匹配 a/b,a//b 和 a///b。
但不会匹配 ab(没有斜杠);也不会匹配a////b(斜杠超过三个)。
你可以省略m或者n,这样的话,引擎会假定一个合理的值代替。
省略m,将被解释为下限0;省略n则会被解释为无穷大(事实上是上边我们提到的20亿)。
小甲鱼解释:
如果是{,n}相当于{0,n};如果是{m,}相当于{m,+无穷};如果是{n},则是重复前一个字符n次。
聪明的鱼油应该已经发现了,其实 *、+ 和 ?
都可以使用 {m,n} 来代替。
{0,} 跟 * 是一样的;{1,} 跟 + 是一样的;{0,1}跟 ?
是一样的。
不过还是鼓励大家记住并使用 *、+ 和 ?
,因为这些字符更短并且更容易阅读。
小甲鱼解释:
还有一个原因是匹配引擎对*+?
做了优化,效率要更高些。
使用正则表达式
(二)
现在我们开始来写一些简单的正则表达式吧。
Python通过re模块为正则表达式引擎提供一个接口,同时允许你将正则表达式编译成模式对象,并用它们来进行匹配。
小甲鱼解释:
re模块是使用C语言编写,所以效率比你用普通的字符串方法要高得多;将正则表达式进行编译(compile)也是为了进一步提高效率;后边我们会经常提到“模式”,指的就是正则表达式被编译成的模式对象。
编译正则表达式
正则表达式被编译为模式对象,该对象拥有各种方法供你操作字符串,如查找模式匹配或者执行字符串替换。
>>>importre
>>>p=pile('ab*')
>>>p
<_sre.SRE_Patternobjectat0x...>
复制代码
pile()也可以接受flags参数,用于开启各种特殊功能和语法变化,我们会在后边一一介绍。
现在我们先来看个简单的例子:
>>>p=pile('ab*',re.IGNORECASE)
复制代码
正则表达式作为一个字符串参数传给pile()。
由于正则表达式并不是Python的核心部分,因此没有为它提供特殊的语法支持,所以正则表达式只能以字符串的形式表示。
(有些应用根本就不需要使用到正则表达式,所以Python社区的小伙伴们认为没有必要将其纳入Python的核心。
)相反,re模块仅仅是作为C的扩展模块包含在Python中,就像socket模块和zlib模块。
使用字符串来表示正则表达式保持了Python简洁的一贯风格,但也因此有一些负面影响,下边我们就来谈一谈。
麻烦的反斜杠
上一篇中我们已经提到了,正则表达式使用'\'字符来使得一些普通的字符拥有特殊的能力(例如\d表示匹配任何十进制数字),或者剥夺一些特殊字符的能力(例如\[表示匹配左方括号'[')。
这会跟Python字符串中实现相同功能的字符发生冲突。
小甲鱼解释:
挺拗口,接着看例子你就懂了~
现在的情况是,你需要在LaTeX文件中使用正则表达式匹配字符串'\section'。
因为反斜杠作为需要匹配的特殊字符,所以你需要再它前边加多一个反斜杠来剥夺它的特殊功能。
所以我们会把正则表达式的字符写成'\\section'。
但不要忘了,Python在字符串中同样使用反斜杠来表示特殊意义。
因此,如果我们想将'\\section'完整地传给pile(),我们需要再次添加两个反斜杠......
匹配字符匹配阶段
\section需要匹配的字符串
\\section正则表达式使用'\\'表示匹配字符'\'
"\\\\section"不巧,Python字符串也使用'\\'表示字符'\'
简而言之,为了匹配反斜杠这个字符,我们需要在字符串中使用四个反斜杠才行。
所以,在正则表达式中频繁地使用反斜杠,会造成反斜杠风暴,进而导致你的字符串极其难懂。
解决方法是使用Python的原始字符串来表示正则表达式(就是在字符串前边加上r,大家还记得吧...):
正则字符串原始字符串
"ab*"r"ab*"
"\\\\section"r"\\section"
"\\w+\\s+\\1"r"\w+\s+\1"
小甲鱼解释:
强烈建议使用原始字符串来表达正则表达式。
实现匹配
当你将正则表达式编译之后,你就得到一个模式对象。
那你拿他可以用来做什么呢?
模式对象拥有很多方法和属性,我们下边列举最重要的几个来讲:
方法功能
match()判断一个正则表达式是否从开始处匹配一个字符串
search()遍历字符串,找到正则表达式匹配的第一个位置
findall()遍历字符串,找到正则表达式匹配的所有位置,并以列表的形式返回
finditer()遍历字符串,找到正则表达式匹配的所有位置,并以迭代器的形式返回
如果没有找到任何匹配的话,match()和search()会返回None;如果匹配成功,则会返回一个匹配对象(matchobject),包含所有匹配的信息:
例如从哪儿开始,到哪儿结束,匹配的子字符串等等。
接下来我们一步步讲解:
>>>importre
>>>p=pile('[a-z]+')
>>>p
pile('[a-z]+')
复制代码
现在,你可以尝试使用正则表达式[a-z]+去匹配各种字符串。
例如:
>>>p.match("")
>>>print(p.match(""))
None
复制代码
因为+表示匹配一次或者多次,所以空字符串不能被匹配。
因此,match()返回None。
我们再尝试一个可以匹配的字符串:
>>>m=p.match('fishc')
>>>m
<_sre.SRE_Matchobject;span=(0,5),match='fishc'>
复制代码
在这个例子中,match()返回一个匹配对象,我们将其存放在变量m中,以便日后使用。
接下来让我们来看看匹配对象里边有哪些信息吧。
匹配对象包含了很多方法和属性,以下几个是最重要的:
方法功能
group()返回匹配的字符串
start()返回匹配的开始位置
end()返回匹配的结束位置
span()返回一个元组表示匹配位置(开始,结束)
大家看:
>>>m.group()
'fishc'
>>>m.start()
0
>>>m.end()
5
>>>m.span()
(0,5)
复制代码
由于match()只检查正则表达式是否在字符串的起始位置匹配,所以start()总是返回0。
然而,search()方法可就不一样咯:
>>>print(p.match('^_^fishc'))
None
>>>m=p.search('^_^fishc')
>>>print(m)
<_sre.SRE_Matchobject;span=(3,8),match='fishc'>
>>>m.group()
'fishc'
>>>m.span()
(3,8)
复制代码
在实际应用中,最常用的方式是将匹配对象存放在一个局部变量中,并检查其返回值是否为None。
形式通常如下:
p=pile(...)
m=p.match('stringgoeshere')
ifm:
print('Matchfound:
',m.group())
else:
print('Nomatch')
复制代码
有两个方法可以返回所有的匹配结果,一个是findall(),另一个是finditer()。
findall()返回的是一个列表:
>>>p=pile('\d+')
>>>p.findall('3只小甲鱼,15条腿,多出的3条在哪里?
')
['3','15','3']
复制代码
findall()需要在返回前先创建一个列表,而finditer()则是将匹配对象作为一个迭代器返回:
>>>iterator=p.finditer('3只小甲鱼,15条腿,还有3条去了哪里?
')
>>>iterator
>>>formatchiniterator:
print(match.span())
(0,1)
(6,8)
(13,14)
复制代码
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 正则表达式 小甲鱼 正则 表达式 甲鱼
![提示](https://static.bingdoc.com/images/bang_tan.gif)