Crossin的编程教室

标题: 【Python 第55课】 正则表达式(1) [打印本页]

作者: crossin先生    时间: 2013-9-16 19:39
标题: 【Python 第55课】 正则表达式(1)
今天来挖个新坑,讲讲正则表达式。

什么是正则表达式?在回答这个问题之前,先来看看为什么要有正则表达式。

在编程处理文本的过程中,经常会需要按照某种规则去查找一些特定的字符串。比如知道一个网页上的图片都是叫做'image/8554278135.jpg'之类的名字,只是那串数字不一样;又或者在一堆人员电子档案中,你要把他们的电话号码全部找出来,整理成通讯录。诸如此类工作,如果手工去做,当量大的时候那简直就是悲剧。但你知道这些字符信息有一定的规律,可不可以利用这些规律,让程序自动来做这些无聊的事情?答案是肯定的。这时候,你就需要一种描述这些规律的方法,正则表达式就是干这事的。

正则表达式就是记录文本规则的代码。

所以正则表达式并不是python中特有的功能,它是一种通用的方法。python中的正则表达式库,所做的事情是利用正则表达式来搜索文本。要使用它,你必须会自己用正则表达式来描述文本规则。之前多次有同学表示查找文本的事情经常会遇上,希望能介绍一下正则表达式。既然如此,我们就从正则表达式的基本规则开始说起。

1.
首先说一种最简单的正则表达式,它没有特殊的符号,只有基本的字母或数字。它满足的匹配规则就是完全匹配。例如:有个正则表达式是“hi”,那么它就可以匹配出文本中所有含有hi的字符。

来看如下的一段文字:
Hi, I am Shirley Hilton. I am his wife.

如果我们用“hi”这个正则表达式去匹配这段文字,将会得到两个结果。因为是完全匹配,所以每个结果都是“hi”。这两个“hi”分别来自“Shirley”和“his”。默认情况下正则表达式是严格区分大小写的,所以“Hi”和“Hilton”中的“Hi”被忽略了。

为了验证正则表达式匹配的结果,你可以用以下这段代码做实验:
  1. import re
  2. text = "Hi, I am Shirley Hilton. I am his wife."
  3. m = re.findall(r"hi", text)
  4. if m:
  5.     print m
  6. else:
  7.     print 'not match'
复制代码
暂时先不解释这其中代码的具体含义,你只要去更改text和findall中的字符串,就可以用它来检测正则表达式的实际效果。

2.
如果我们只想找到“hi”这个单词,而不把包含它的单词也算在内,那就可以使用“\bhi\b”这个正则表达式。在以前的字符串处理中,我们已经见过类似“\n”这种特殊字符。在正则表达式中,这种字符更多,以后足以让你眼花缭乱。

“\b”在正则表达式中表示单词的开头或结尾,空格、标点、换行都算是单词的分割。而“\b”自身又不会匹配任何字符,它代表的只是一个位置。所以单词前后的空格标点之类不会出现在结果里。

在前面那个例子里,“\bhi\b”匹配不到任何结果。但“\bhi”的话就可以匹配到1个“hi”,出自“his”。用这种方法,你可以找出一段话中所有单词“Hi”,想一下要怎么写。

3.
最后再说一下[]这个符号。在正则表达式中,[]表示满足括号中任一字符。比如“[hi]”,它就不是匹配“hi”了,而是匹配“h”或者“i”。

在前面例子中,如果把正则表达式改为“[Hh]i”,就可以既匹配“Hi”,又匹配“hi”了。


#==== Crossin的编程教室 ====#
微信ID:crossincode
论坛:http://crossin.me
QQ群:156630350

面向零基础初学者的编程课
每天5分钟,轻松学编程



作者: Miracle_Wong    时间: 2013-9-16 20:50
学习了,最近论坛不是很稳定,抓紧学习
作者: dark    时间: 2013-9-16 23:23
猜测re.findall(r"hi", text)中的r是read的意思。。那难道还有w...
作者: dark    时间: 2013-9-16 23:23
re.findall(r"hi", text)猜测其中的r是read意思,这么说难道也有w。。。
作者: crossin先生    时间: 2013-9-16 23:47
dark 发表于 2013-9-16 23:23
re.findall(r"hi", text)猜测其中的r是read意思,这么说难道也有w。。。

错了,是raw的意思
作者: aresli    时间: 2013-9-17 15:28
正则这个东西如果没有一个环境让你持续的思考记忆个半年,是很难掌握好的。
我建议正则课程结束后,是不是应该开一个置顶的正则的练习贴的帖子,老师和同学都可以把自己的联系题发上去,不用多,一周有个1-2题就可以了。
只有持续的练习才能掌握的更好。
作者: crossin先生    时间: 2013-9-17 16:36
aresli 发表于 2013-9-17 15:28
正则这个东西如果没有一个环境让你持续的思考记忆个半年,是很难掌握好的。
我建议正则课程结束后,是不是 ...

ok
课程里只能大概解释一下原理和规则,要想掌握,还得用很久才能熟悉。
作者: michael    时间: 2013-10-2 00:12

作者: liu-pengfei    时间: 2014-9-27 00:53
我感觉一定要用的多才行。
作者: l0ve1o24    时间: 2017-1-13 14:36
在前面那个例子里,“\bhi\b”匹配不到任何结果。但“\bhi”的话就可以匹配到1个“hi”,出自“his”。用这种方法,你可以找出一段话中所有单词“Hi”,想一下要怎么写。


这个怎么没有同学回答啊?到底应该怎么写?
  1. import re
  2. text = "Hi, I am S hirley Hilton. I am his wife."
  3. m = re.findall(r'\bhi', text)
  4. if m:
  5.     print m
  6. else:
  7.     print 'not match'
复制代码
实在想不出来,在这S hirley加了个空格

作者: crossin先生    时间: 2017-1-14 14:46
l0ve1o24 发表于 2017-1-13 14:36
在前面那个例子里,“\bhi\b”匹配不到任何结果。但“\bhi”的话就可以匹配到1个“hi”,出自“his”。用这 ...

没明白你的意思,你想匹配哪一个?
\bhi\b 是匹配单词hi,不包括其他词中间的,这个没错。\bhi 就是匹配单词开头的 hi
作者: l0ve1o24    时间: 2017-1-14 20:36
crossin先生 发表于 2017-1-14 14:46
没明白你的意思,你想匹配哪一个?
\bhi\b 是匹配单词hi,不包括其他词中间的,这个没错。\bhi 就是匹配 ...

没有,你前面不是提了个问题吗?我看没同学解答,看了后面的课,差不多知道了
作者: tanlongfei    时间: 2017-8-11 15:32
有个问题,python3里,直接用r‘hi’,出来的就是\bhi\b的效果。。。就是只输出hi,不输出包括hi的单词。。。这个应该怎么输出包括hi的单词
  1. import re
  2. text = 'Hi,I am Shirly Hilton.I am his wife.'
  3. m = re.findall(r'hi',text)
  4. print(m)
复制代码

作者: crossin先生    时间: 2017-8-11 23:49
tanlongfei 发表于 2017-8-11 15:32
有个问题,python3里,直接用r‘hi’,出来的就是\bhi\b的效果。。。就是只输出hi,不输出包括hi的单词。。 ...

和py3无关,hi就是匹配hi呀,包含的单词,那你前后得加上通配符(往后面两课继续看下去)
作者: tanlongfei    时间: 2017-8-17 21:10
嗯嗯,谢谢crossin先生,这两天没上,之前那个问题自己看了后面的明白了。
又有了新的问题,我现在在做练习题,抓取豆瓣推荐电影的练习题,然后代码已经写完,这个网址一共十页。非常奇怪的是,自动循环运行前八页的时候,都能顺利进行,运行第九页的时候,告诉我list长度出了问题,我然后自己看了下出问题的地方,长度正确,不知道问题出在了哪,麻烦crossin先生或者哪位大神给看下。
  1. #https://movie.douban.com/top250?start=0&filter=
  2. #上面这个网址以start跳动25翻页
  3. import urllib.request
  4. import re
  5. import time

  6. #这是抓取的函数
  7. def zhua(mum):
  8.     #抓取电影,之后把这部分写成函数形式
  9.     url = 'https://movie.douban.com/top250?start=%d&filter='%num
  10.     web = urllib.request.urlopen(url).read().decode('UTF-8')
  11.     content = str(web)
  12.     #电影名
  13.     titles = re.findall(r'<span class="title">\w+',content)
  14.     titles = [i[20:] for i in titles]  #此句为去除匹配电影名时的特定词
  15.     #导演
  16.     daoyan = re.findall(r'导演:\s[^&]+',content)
  17.     #主演
  18.     actors = re.findall(r'主[^<]+',content)
  19.     #上映日期
  20.     playtime = re.findall(r'\s{29}[0-9]+',content)
  21.     playtime = [i[29:] for i in playtime]
  22.     #产地和剧情
  23.     candj = re.findall(r'&nbsp;/&nbsp;.*&nbsp;/&nbsp;.*',content)
  24.     chandi = []
  25.     juqing = []
  26.     for i in range(0,25):
  27.         chandi.append(candj[i].split('&nbsp;/&nbsp;')[1])
  28.         juqing.append(candj[i].split('&nbsp;/&nbsp;')[1])
  29.     #一句话影评
  30.     yp = re.findall(r'<span class="inq">[^<]+',content)
  31.     yp = [i[18:] for i in yp]
  32.     outdata = []
  33.     for i in range(0,25):
  34.         outdata.append('电影名 '+titles[i]+'\n'\
  35.                        +daoyan[i]+'\n'+actors[i]+'\n'\
  36.                        +'上映日期 '+playtime[i]+'\n'\
  37.                        +'产地/语言 '+chandi[i]+'\n'\
  38.                        +juqing[i]+'\n'\
  39.                        +'影评 '+yp[i]+'\n\n')
  40.     out = open('out.txt','a',encoding='utf-8')
  41.     for i in outdata:
  42.         out.write(i)
  43.     out.close()


  44. #接下来是设计循环运行十次
  45. for i in range(0,10):
  46.     print(i)
  47.     num = i*25
  48.     zhua(num)
复制代码
出现的问题是:
  1. Traceback (most recent call last):
  2.   File "C:\Users\T\Desktop\913抓取豆瓣电影.py", line 51, in <module>
  3.     zhua(num)
  4.   File "C:\Users\T\Desktop\913抓取豆瓣电影.py", line 40, in zhua
  5.     +'影评 '+yp[i]+'\n\n')
  6. IndexError: list index out of range
  7. >>>
复制代码
谢谢
作者: crossin先生    时间: 2017-8-17 23:06
tanlongfei 发表于 2017-8-17 21:10
嗯嗯,谢谢crossin先生,这两天没上,之前那个问题自己看了后面的明白了。
又有了新的问题,我现在在做练习 ...

这个从代码看不出来。你得自己调试,把 yp 输出出来看看是什么
有些电影的数据是没有的
作者: tanlongfei    时间: 2017-8-18 11:11
crossin先生 发表于 2017-8-17 23:06
这个从代码看不出来。你得自己调试,把 yp 输出出来看看是什么
有些电影的数据是没有的 ...

嗯,先谢谢你那么晚还回复。。。
我那个是调试以后的,yp是当页25部电影的影评。正常来说,yp应该是一个长度为25的list,事实上,我在单独运行那一页的数据后,也是长度为25的list。然后就不知道为什么老是出错。
还有个需要注意的是,我觉得问题不在yp这,因为如果我把yp从函数的循环里删除了,理论上也是可以正常运行的,就是每个电影没有影评罢了,然后在那页还是会出错,出错原因还是一样的,只是出错的地方成了juqing这里,也是反馈说out of range。。。
然后把juqing也去了,反馈上一个chandi同样的问题。。。。
不知道你碰到过这样的情况吗,或者你知道该怎么解决吗
作者: tanlongfei    时间: 2017-8-18 11:22
crossin先生 发表于 2017-8-17 23:06
这个从代码看不出来。你得自己调试,把 yp 输出出来看看是什么
有些电影的数据是没有的 ...

crossin先生,我找到问题了,是有个list不是25长度,但是不是yp。原来分行写的语句不管哪行出了问题都显示最后一行出问题。。。。
谢谢你啦,打扰了
作者: blueheart    时间: 2017-8-25 09:21
本帖最后由 blueheart 于 2017-8-25 09:23 编辑

请问Crossin先生为什么print  "\bhi"会打印出乱码出来的? re1.png


作者: crossin先生    时间: 2017-8-25 09:32
blueheart 发表于 2017-8-25 09:21
请问Crossin先生为什么print  "\bhi"会打印出乱码出来的?

\b 是有特殊含义的字符,被转义了,所以要加 r
作者: shaonan    时间: 2017-9-24 22:38
  1. # 正则表达式
  2. import re
  3. text = 'hi, my name is him. I na am 23 years old.'
  4. result = re.findall('\\bhi',text)
  5. if result:
  6.     print result
  7. else:
  8.     print 'there is no match!'
复制代码
之前无脑的直接
  1. result = re.findall('\bhi',text)
复制代码
然后一直无匹配。。。忘记了在引号里要多加一个\ 了。。。。
作者: shaonan    时间: 2017-9-24 23:03
shaonan 发表于 2017-9-24 22:38
之前无脑的直接然后一直无匹配。。。忘记了在引号里要多加一个\ 了。。。。 ...

请问我分析的对吗。。看了第二课又有些疑问。。
作者: crossin先生    时间: 2017-9-25 11:32
shaonan 发表于 2017-9-24 23:03
请问我分析的对吗。。看了第二课又有些疑问。。

对的。或者在规则前面加上 r,避免字符串的转义
作者: shaonan    时间: 2017-9-26 22:12
crossin先生 发表于 2017-9-25 11:32
对的。或者在规则前面加上 r,避免字符串的转义

你好,我提出疑问的原因是我发现对于\S来说,\\S和\S没有区别:
  1. # 匹配所有s开头e结尾的单词 且单词字母大于2
  2. text = 'site sea sue sweet see case se ssee loses lsre'
  3. result = re.findall('\\bs\S+?e\\b',text)
  4. if result:
  5.     print result
  6. else:
  7.     print 'there is no match!'[/code

  8. [code]
  9. # 匹配所有s开头e结尾的单词 且单词字母大于2
  10. text = 'site sea sue sweet see case se ssee loses lsre'
  11. result = re.findall('\\bs\\S+?e\\b',text)
  12. if result:
  13.     print result
  14. else:
  15.     print 'there is no match!'
复制代码
这两段程序运行结果相同,怎么解释呢?
作者: crossin先生    时间: 2017-9-26 22:54
shaonan 发表于 2017-9-26 22:12
你好,我提出疑问的原因是我发现对于\S来说,\\S和\S没有区别:这两段程序运行结果相同,怎么解释呢? ...

因为 \S 不存在对应的字符转义
作者: shaonan    时间: 2017-9-27 09:45
crossin先生 发表于 2017-9-26 22:54
因为 \S 不存在对应的字符转义

受教。。希望能变成你这样得人。。




欢迎光临 Crossin的编程教室 (https://bbs.crossincode.com/) Powered by Discuz! X2.5