黑马程序员技术交流社区

标题: 正则表达式随记 [打印本页]

作者: 小夕酱    时间: 2018-10-24 00:53
标题: 正则表达式随记
本帖最后由 小夕酱 于 2018-10-24 12:33 编辑

   看之前一期二期基础班毕业了都发表一下感想,我这个三期的也来凑凑热闹
   关于学习方法我这里就不去多说太多,希望每个人能找到自己的方法,毕竟自己的节奏自己做主(PS:不要被外界的言语所干扰,也不要被班班说休息那天都没人来,你看看Java班的都来了一半一半啥的,自己掌握好自己的节奏,想休息就休息,不要把不适合自己的方法强行压在自己的身上那样不仅效率不高,也白白浪费一天的休息时间。不以物喜,不以己悲,宏观可以这么理解,大家好好加油)
   那么我的学习方法有针对性了,之前因为接触过一些爬虫,对爬虫有着浓厚的兴趣,所以关于Web的知识我则是以理解为主。我更注重了代码的逻辑思想,在Web方面的学习我投入了较小的精力。而在爬虫的学习中我会投入200%的精力。爬虫最为关键的就是正则表达式
   那么说到正则表达式,关于爬虫最为关键的就是精通正则/Xpath等表达式,正则的应用更为广泛,Xpath则是针对了爬虫爬取信息筛选。无正则不爬虫,从下面的部分招聘信息不难看出爬虫这个岗位对于正则的要求,而且爬虫将来转型也是稍有前景:爬虫——>数据筛选——>数据分析——>科学计算
        此篇笔记基于老师的讲义以及自己对正则的理解整理而成,有不足的地方请谅解
1、正则表达式在Python中有个专门的库叫re模块,首先进行导入模块。再定义一个字符串str,然后定义一个正则表达式匹配规则regex。
2、“^d”代表的意思是以d元素开头的任意一个字符串,也就是说只要是以d开头的字符串,后面的元素不论是什么,都是符合规则的,总之必须要以d开头。
3、“.” 较为常用,其代表的意思是任意字符,其表示的范围非常广,可以接任意字符,不论是中英文,还是下划线之类的特殊字符,都是可以代表的。举个例子,正则表达式“^d.”就是代表以d开头的字符串,b后边接任意字符都可以。
4、“*” 也十分常用,其代表的意思是前面的字符可以重复任意多遍,可以是0次,1次,2次等任意多次。
5、了解好这几个特殊字符的用法之后,接下来通过代码简单的感受一下。如下图所示,如果匹配成功,则返回yes;如果没有匹配成功,则不返回任何东西。
      可以看到程序运行之后,返回的结果为yes,说明匹配成功。正则表达式“^d.*”代表的意思是以d开头的字符串,后面跟着任意字符,出现任意多遍。显然,通过匹配可以得知该正则表达式匹配的结果和原始字符串一致,之后if判断返回值为true,所以打印出结果为yes。
    6、为了进一步验证这个模式是否正确,我们将d改为a,其代表的意思该模式下的字符串是否以a开头的。之后再次运行程序,如下图所示。
此时可以看到无任何输出,说明特殊字符“^”起到了作用。
7、特殊字符“$”代表的意思是结尾字符。举个例子,正则表达式“4$”,表示匹配以4为结尾的字符串。代码演示如下图所示。
正则表达式匹配模式“.*4$”代表以4结尾的任意字符的字符串,很显然匹配的结果和原始字符串是一致的,所以有返回结果。
8、如果将正则表达式匹配模式改为“.*3$”,则表示以3结尾的任意字符的字符串,此时是没有任何的输入结果的,如下图所示。
9、正则表达式特殊字符“?”比较常用,其代表的意思是非贪婪匹配模式。默认情况下,匹配字符串是一种贪婪的匹配,换句话说,默认情况下字符串会根据匹配模式,去匹配最大的长度。
10、下图是一个实例。其中括号代表的是提取字符串的子串,正则表达式会把满足匹配条件的字符串放到括号里边。匹配模式“.*(p.*p).*”代表的意思是:左边的“.* ”的意思是任意字符串,可以是空,也可以是非空的字符串,之后是字符p,中间的“.* ” 的意思也是任意字符串,之后再是一个p,尔后右边的“.* ” 的意思也是任意字符串。目前的逻辑就是将两个p中间的字符串连同p一块取出。
但是其输出的结果却为“pp”,并不是我们想要的“pcccccccccp”结果。原因是正则表达式的贪婪匹配所致,实际上它是反向匹配的,所以从字符串来看,匹配到的结果是“pp”。
11、如果我们使用非贪婪模式,即将匹配模式“.*(p.*p).*”改为模式“.*?(p.*p).*”,在第一“p”之前加个特殊字符“?”,则运行的结果就如下图所示。
可以看到匹配模式已经开始从左边开始进行匹配,答案趋向于我们想要的结果。但是在后面却出现了两个p。原因是后面的那个p未指定其为非贪婪模式,所以后面的那个p仍然是从右边开始反向取值的。
12、我们继续使用非贪婪模式,即将匹配模式“.*(p.*p).*”改为模式“.*?(p.*?p).*”,在第二“p”之前也加个特殊字符“?”,则运行的结果就如下图所示。
此时可以看到匹配的结果就是我们想要的结果了,原因是此时两个p均采用了非贪婪模式,所以匹配模式,从左到右顺序进行。
13、理解非贪婪模式之后,对于正则表达式的匹配就很好理解了,如下图的结果将返回“pcccp”,非贪婪模式下。
14、下图的结果将返回“pcccpcccccccpppp”,非贪婪模式和贪婪模式共存的情况下。
非贪婪模式在网络爬虫的过程中对于字符串的提取非常重要,务必要理解和掌握。

15、正则表达式特殊字符“+”,其代表的意思“+”号前面的任意字符必须至少出现一次,才能匹配成功。如下图所示,如果没有加特殊字符“+”,则按照前面介绍的贪婪模式从右边进行匹配,输出的结果为“pp”。

16、现在将匹配模式由之前的“.*(p.*p).*”改为“.*(p.+p).*”,即将特殊字符“*”改为特殊字符“+”,用特殊字符“+”来限定前面的字符出现的次数,至少出现一次。运行程序,得到的结果为“ppp”,如下图所示。

简单的来理解一下,匹配到第一个字符p,之后碰到特殊字符“+”,表示匹配任意字符,但该字符至少出现一次,然后再匹配到第二个字符p,才会提取到匹配的字符串。

17、将之前的三个ppp改为现在的php,之后再运行程序,如下图所示,得到的结果是php。


18、如果将之前的三个ppp改为现在的phhp,会有什么样的结果呢?如下图所示,毋庸置疑,答案肯定是phhp。


因为特殊字符“+”号表示只要任意字符至少出现一次,都会被提取出来。

19、简单的来总结一下,特殊字符“*”和特殊字符“+”都是用来表示字符出现次数的限定词,用于限定前面的任意字符出现的次数。不同的地方在于特殊字符“*”模式下,字符出现的次数可以是0次或者任意多次,而特殊字符“+”模式下,字符出现的次数至少是1次。

20、特殊字符“{}”实质上也是一个限定词的用法,其限定前面字符所出现的次数,其常用的模式有三种,分别是“{数字}”、“{数字,}”和“{数字1, 数字2}”。举个例子,如“{1}”、“{1,}”和“{1, 3}”。如下图所示,限定字符p前面的字符出现1次,则根据贪婪匹配模式,pap成功匹配到。
21、如果将匹配模式更改为“.*(p.{2}p).*”,则无任何的输出,如下图所示,因为此时并没有任何的字字符串符合匹配条件

22、相应的,我们将原始字符串做一下更改,如下图所示,此时“.*(p.{2}p).*”匹配模式有对应的结果,如下图所示。


23、特殊字符“{1,}”代表的是前面的字符出现1次及以上;特殊字符“{2,}”代表的是前面的字符出现2次及以上;特殊字符“{3,}”代表的是前面的字符出现3次及以上;以此类推。举个例子,如下图所示。



我们要匹配出现p字符前面出现3次及以上的次数,此时子字符串phhhhp被提取出来,但是pap和paap都没有提取到,因为其不满足匹配条件。
24、特殊字符“{1, 3}” 代表的是前面的字符至少出现1次,最多出现3次;特殊字符“{2, 5}” 代表的是前面的字符至少出现2次,最多出现5次;以此类推。举个例子,如下图所示。
当使用特殊字符“{1, 3}”的时候,如下图所示:



贪婪模式下,字符串从右边开始往左取,首先遇到相对满足条件的子字符串是phhhhp,但是并不符合规则,因为该子字符串出现的次数为4次,而限定条件为1次到3次,所以这个子字符串不符合匹配条件,然后继续往前匹配,得到匹配结果paap,满足匹配条件。
同理,当使用特殊字符“{3, 5}”的时候,如下图所示:

根据上一步的分析可以得知,该匹配结果为phhhhp。

25、竖线“|”实质上是一个或的关系。比方说我们需要匹配一个字符串“xiaoxi123”,匹配模式为 “(xiaoxi|xiaoxi123)”,记得匹配模式中要有括号,否则后面的group方法会报错。




如上图所示,匹配模式“(xiaoxi|xiaoxi123)”的意思是只要匹配“xiaoxi”或者“xiaoxi123”中的任意一个,就说明提取成功。“|”实质上是一个“或”的关系,匹配的结果为“xiaoxi”可以满足匹配条件,匹配的结果为“xiaoxi123”也可以满足匹配条件。所以在这里,正则表达式首先匹配了字符串“xiaoxi”,所以打印出来的结果就是“xiaoxi”。

26、当我们把匹配模式中两个字符串的顺序调整一下,如下图所示。



27、如果我们将原始字符串做一下更改,更改为“xiaoxi”,而保持匹配模式不变,如下图所示。




此时的匹配结果为“xiaoxi”。原因是匹配模式首先是“xiaoxi123”,与原始字符串匹配不上,之后通过特殊字符“|”再定位到“xiaoxi”,发现可以与原始字符串匹配上,所以匹配成功,输出匹配结果。

28、如果我们只是想匹配字符串中的一部分,如下图所示,只需要将匹配模式用括号括起来就可以了,而括号外面的部分保持与原始字符串一致即可。



此时可以看到输出的结果为“xiaoxi”。这里容易踩到坑,可能大多数人很可能以为结果是“xiaoxi123”,只需要记住我们匹配的内容只是在括号中,外边的世界与我们无关。
同样的,如果我们将原始字符串改为“xiaoxixi123”,保存匹配模式不变,此时的匹配结果为“xiaoxixi”,如下图所示。


29、如果真想匹配到外边的结果,就应该再加一层括号,将外边的内容与括进来,如下图所示。当程序运行之后,我们得到的匹配结果是“xiaoxixi123”。


当程序运行之后,实际上是以最外层的这个括号为顺序的,然后依次向内进行匹配。当group方法中取第一个括号的内容时,匹配到的结果是最外层括号中的内容,所以是“xiaoxixi123”。可以看到“123”也被提取出来了。
同理,当group方法中取第二个括号的内容时,匹配到的结果是最二层括号中的内容,所以是“xiaoxixi”,如下图所示。


此时可以看到“123”并没有被提取出来,因为此时匹配的内容是“(xiaoxi|xiaoxixi)”。
30、正则表达式特殊符号“[]”中括号十分实用,其有特殊含义,其代表的意思是中括号中的字符只要满足其中任意一个就可以。其用法一共有三种,分别对其进行具体的代码演示,如下图所示,匹配模式为[abcd],在这里正则表达式代表的意思是字符串第一个字符是abcd四个字符中的任意一个,然后后面的字符是“xiaoxi123”,如果满足匹配条件,则输出结果,如果不满足,则不显示任何结果,如下图所示。


很显然原始字符串的第一个字符是a,和匹配模式相接,所以输出结果。
31、为了更好的加强理解,现在将原始字符串改为“cxiaoxi123”,其他部分不做改动,如下图所示。


可以看到匹配的结果是“cxiaoxi123”,匹配成功。
32、为进一步理解中括号的意思,现在将原始字符串改为“exiaoxi123”,其他部分不做改动,如下图所示。

此时可以看到没有任何结果输出,因为在中括号中没有对应的匹配字符,满足不了匹配要求,所以无任何输出。
33、看下面一个例子,提取电话号码,这个在实际应用中十分常见。在这里介绍中括号的另外一种表达方式即[0-9],这个特殊字符代表的意思是数字0到9中的任意一个字符。下面的匹配模式'(1[34578][0-9]{9})'代表的意思是字符串以1开头,然后第二个字符为3、4、5、7、8中任意一个,之后的字符是0到9中的数字,但是限定为9次,也就是说电话号码的长度为1+1+9=11位。如果满足上面的匹配要求,就输出成功,否则就不输出任何的字符。


如上图,很明显原始字符串满足匹配的要求,所以有输出结果。
Tips:[a-z]代表26个英文小写字母;[A-Z]代表26个英文大写字母。
34、如果将原始字符串改为160开头的号码,然后进行输出,如下图所示。


可以看到无任何输出结果。
35、中括号的第三个用法是[^],在中括号中加入特殊字符“^”,表示非,取反的意思。举个例子,“[^1]”的意思是字符不等于1,下图是代码演示。


可以看到原始字符串与匹配模式'(1[34578][^1]{9})'匹配成功,因为从第二个字符之后,字符串中就没有1出现,符合匹配规则。
即便是原始字符串中出现非数字的字符,只要不是1,也能够匹配成功,如下图所示。


36、那么先将原始字符串中的号码改为‘18356070671’,在字符串后边加个1,然后匹配模式不改变,如下图所示。


37、“s”代表的意思是匹配空格,匹配模式“加s油”代表的是字符“加”和“油”之间有空格的意思,如下图所示。


可以看到原始字符串中“加”和“油”之间有空格,与匹配条件相符合,所以匹配成功。
38、那么现在将原始字符串改为“加加油”,字符中间不为空格,保持匹配模式不变,如下图所示。


可以看到无任何输出,说明匹配不成功。
39、如果“加”和“油”之间有多个空格的话,则只需要在匹配模式中将“加s油”改为“加s+油”即可,如下图所示。


40、“S”代表的意思与“s”代表的意思刚刚相反,也就是说匹配的那个字符只要不是空格,都可以匹配。如下图所示,继续用第二步那个例子,只要将匹配模式中的“s”改为“S”,其他的保持不变,如下图所示。


可以看到此时就可以匹配成功。
41、而将原始字符串改为“加 油”,两个字符中间有个空格,匹配模式不变,如下图所示。


可以看到此时无任何输出,说明匹配不成功。
42、同样的,如果要匹配多个非空白字符的话,只需要将“S”改为“S+”即可,如下图所示。


43、“\w”代表的意思是该字符为任意字符,但是和特殊字符“.”的意思不同。“\w”代表的字符主要包括26个大写字母A到Z,即[A-Z]、26个小写字母a到z,即[a-z]、10个阿拉伯数字0到9,即[0-9]和下划线“_”。总结起来就是,“\w”代表的意思是[A-Za-z0-9_]中任意一个字符。“.” 代表的意思是任意字符,其范围比“\w”代表的意思要广。


可以看到此时用的是特殊字符中括号来代替特殊字符“\w”,匹配成功。
44、现在将[A-Za-z0-9_]改为\w,如下图所示。


可以看到仍然可以匹配成功。
45、将原始字符串改为“加A油”,如下图所示。


可以看到仍然可以匹配成功。
46、将原始字符串改为“加_油”,如下图所示。


可以看到仍然可以匹配成功。
47、当将原始字符串改为“加-油”,如下图所示。


可以看到此时就不可以匹配成功了,因为字符“-”并在包括在\w涵盖的范围之内。
48、“\W”代表的意思与“\w”刚刚相反,也就是匹配除了[A-Za-z0-9_]之外的其他字符。接上一步的例子,此时将“\w”改为“\W”,如下图所示。

可以看到此时就匹配成功了。

49、将原始字符串“加-油”改为“加 油”,中间有空格,其他保持不变,如下图所示。


很显然,使用“\w”肯定不能匹配成功,但使用“\W”便可以成功的进行匹配。



作者: 小夕酱    时间: 2018-10-24 01:14
本帖最后由 小夕酱 于 2018-10-24 12:35 编辑

暂时只有这么多,有哪些不足大家可以在下面补充我会依次补充
作者: 走散了的鱼    时间: 2018-10-24 13:25
厉害了,小夕酱
作者: itmonster_贼帅    时间: 2018-11-11 08:57
优秀啊,顶顶
作者: 阿蕊    时间: 2018-11-25 15:45
哇哦哦你是真的很棒棒哟
作者: 阿蕊    时间: 2018-11-25 15:46
以后可以继续更新哟
作者: fhw619225600    时间: 2018-11-25 17:30
厉害····················
作者: fhw619225600    时间: 2018-11-25 17:54
······················
作者: 大蓝鲸小蟀锅    时间: 2018-11-26 15:45
播仔认为你很棒
作者: 秒杀女神    时间: 2018-11-26 15:46
厉害
作者: zhangsiyuan    时间: 2018-11-26 15:52
小伙子厉害啊,不仅自己学习还给别人分享,棒棒的!
作者: zhangsiyuan    时间: 2018-11-26 15:53
精神可嘉,棒棒的!
作者: zhangsiyuan    时间: 2018-11-26 15:53
播仔送你一朵小fafa
作者: zhangsiyuan    时间: 2018-11-26 15:54
坐等更新,嘻嘻嘻嘻,大神
作者: 阿蕊    时间: 2018-11-26 19:19

作者: 阿蕊    时间: 2018-11-26 19:20
期待更多这样的技术帖
作者: LEE7    时间: 2018-11-26 19:30
小伙子厉害呀
作者: LEE7    时间: 2018-11-26 19:30
成功的唯一秘诀——坚持到最后一分钟。
作者: LEE7    时间: 2018-11-26 19:32
当你跌到谷底时,那正表示,你只能往上,不能往下!
作者: LEE7    时间: 2018-11-26 19:33
如果你的梦想还站着的话,那么没有人能使你倒下。
作者: LEE7    时间: 2018-11-26 19:33
时间是有限的,所以不要把时间浪费在走别人的路上。
作者: 阿蕊    时间: 2018-11-29 18:51
小夕酱冲鸭




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2