正则表达式(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匹配任何空白字符(包含空格、换行符、制表符等);相当于类[\t\n\r\f\v]\S与\s相反,匹配任何非空白字符;相当于类[^\t\n\r\f\v]\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会怎样?步骤匹配说明1a匹配RE的第一个字符'a'2abcbd引擎在符合规则的情况下尽可能地匹配[bcd]*,直到该字符串的结尾3失败引擎尝试匹配RE最后一个字符'b',但当前位置已经是字符串的结尾,所以失败告终4abcb回退,所以[bcd]*匹配少一个字符5失败再一次尝试匹配RE最后一个字符'b',但字符串最后一个字符是'd',所以失败告终6abc再次回退,所以[bcd]*这次只匹配'bc'7abcb再一次尝试匹配字符'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}跟?是一样的。不过还是鼓励大家记住并使用*、+和?,因为这些字符更短并且更容易阅读。小甲鱼解释:还有一个原因是匹配引擎对*+?做了优化,效率要更高些。