当前位置:文档之家› 正则表达式 小甲鱼

正则表达式 小甲鱼

正则表达式介绍(一)正则表达式(Regular expressions 也称为 REs,或 regexes 或 regex patterns)本质上是一个微小的且高度专业化的编程语言。

它被嵌入到 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 的。

下边列举一些反斜杠加字符构成的特殊含义:它们可以包含在一个字符类中,并且一样拥有特殊含义。

例如 [s,.] 是一个字符类,它将匹配任何空白字符(/s 的特殊含义),',' 或 '.'。

最后我们要讲的一个元字符是 .,它匹配除了换行符以外的任何字符。

如果设置了re.DOTALL 标志,. 将匹配包括换行符在内的任何字符。

重复的事情使用正则表达式能够轻松的匹配不同的字符集合,但 Python 字符串现有的方法却无法实现。

然而,如果你认为这是正则表达式的唯一优势,那你就 too young too native 了。

正则表达式有另一个强大的功能,就是你可以指定 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 会怎样?最灵活的应该是元字符 {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)也是为了进一步提高效率;后边我们会经常提到“模式”,指的就是正则表达式被编译成的模式对象。

编译正则表达式正则表达式被编译为模式对象,该对象拥有各种方法供你操作字符串,如查找模式匹配或者执行字符串替换。

>>> import re>>> p = pile('ab*')>>> p<_sre.SRE_Pattern object at 0x...>复制代码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 字符串也使用 '\\' 表示字符 '\'简而言之,为了匹配反斜杠这个字符,我们需要在字符串中使用四个反斜杠才行。

相关主题