Python之正则表达式(re模块)

正则表达式 (re模块)—— 字符串匹配的

  学习使用re模块来操作正则表达式。

  首先通过例子来看一下使用正则的优越性。

       1.普通方法实现

    while True:
        phone_number = input('please input your phone number : ')
        if len(phone_number) == 11 \
                and phone_number.isdigit()\
                and (phone_number.startswith('13') \
                or phone_number.startswith('14') \
                or phone_number.startswith('15') \
                or phone_number.startswith('18')):
            print('是合法的手机号码')
        else:
            print('不是合法的手机号码')
View Code

  2.正则实现

    import re   #导入正则模块
    phone_number = input('please input your phone number : ')#初始输入
    if re.match('^(13|14|15|18)[0-9]{9}$',phone_number):#正则匹配验证判断
            print('是合法的手机号码')
    else:
            print('不是合法的手机号码')
View Code

  通过上面两种方法可以明显看出正则所具有的优越性。

  为了使特殊字符显示本来的样子,这里通过在特殊字符串前加'r'来实现。

    print(r'\\n')
    print(r'\n')
View Code

1.1 python正则表达式中的元字符

  python中特殊字符有    \.^$?+*{}[]()| 

  1.1.1 字符类速记

^ 在起始处匹配,也可以在带MULTILINE标记的每个换行符后匹配
- 表示一个字符范围,如果作为字符类中的第一个字符,就表示一个字面意义上的连字符
. 可以匹配除换行符之外的任意字符,或带re.DOTALL标记的任意字符,或匹配字符类内部的字面意义的字符
\d 匹配一个Unicode数字,或带re.ASCII标记的[0-9]
\D 匹配一个Unicode非数字,或带re.ASCII标记的[^0-9]
\s 匹配Unicode空白,或带re.ASCII标记的[\t\n\r\f\v]
\S 匹配Unicode非空白,或带re.ASCII标记的[^\t\n\r\f\v]
\w 匹配一个Unicode单词字符,或带re.ASCII标记的[a-zA-Z0-9_]
\W 匹配一个Unicode非单词字符,或带re.ASCII标记的[^a-zA-Z0-9_]
\b  在单词边界匹配,受re.ASCII影响,如果在字符内部则是backspace的转义字符
\B  在非单词边界匹配,受re.ASCII影响
$ 在结尾处匹配,也可以在带MULTILINE标记的每个换行符前匹配
* 重复匹配零次或者更多次(贪婪模式).贪婪模式:尽可能多的匹配遇到的重复。
(?:……) 该子组匹配的字符串无法从后边获取
+ 重复匹配1次或者更多次(贪婪模式)
重复匹配0次或者1次(贪婪模式).
\\ 转义特殊字符或表示特殊序列
[] 表示一组字符,如果以"^"为第一个字符,表示一组字符的互补集
[^] 除了字符组内的其他都匹配
| A|B, 选择分支,或者匹配A或者匹配B
(...) 匹配一个分组,将括号中的内容当作一个整体来对待
(?P<name>...)  组匹配的子字符串,可以能一个名称访问.
(?P=name) 对指定的组反向的引用,以前面的以name为名称的组匹配的文本为分组内容,匹配后面的内容
(?=...) 当该表达式匹配成功的时候,它的前面的表达式才会匹配
(?!...) 当该表达式不匹配的时候,它的前面的表达式都会匹配成功
(?<=...) 匹配以...开始的后面部分的字串,只能是固定的长度,也就是一个明确的表达式.说明:该模式不能于一个字符串的开始
(?<!...) 匹配不是以...开始的后面部分的字串.只能是固定的长度
(?(id/name)yes|no) (?(id/name)yes|no) 如果前面以id/name表示的正则匹配,则利用yes处的正则表达式匹配后面的字符串,否则用no处的匹配

  1.1.2 量词

    格式{m,n},m与n分别表示使用该量词的表达必须匹配的最少次数与最多次数。如果只给定一个数字则同时表示最小值最大值
量词速记形式:

e{m} 准确匹配表达式e的m次出现
e{m,} 贪婪地匹配表达式e至少m次出现
e{m,}? 非贪婪地匹配表达式e至少m次出现
e{,n}  最多n次出现
e{,n}?  贪婪
e? e{0,1}
e?? e{0,1}?
e+   e{1,}
e+? e{1,}?
e*  e{0,}
e*? e{0,}?
.*?abc 一直取遇到abc就停
[]   匹配[]内的任意一个内容
() 将()的内容作为一个整体来进行匹配

    贪婪表示会尽可以多的匹配符合条件的字符,非贪婪则为尽可以少的匹配。

  1.1.3 正则表达式模块标记

re.A 或 re.ASCII   
re.I 或 re.IGNORECASE 忽略大小写
re.M 或 re.MULTILINE 使^在起始处并在每个换行符后匹配,使$在结尾处但在每个换行符之前匹配
re.S 或 re.DOTALL     使.匹配每个字符,包括换行符
re.X 或 re.VERBOSE     使空白与注释包含在匹配中

1.2 RE之findall方法

   返回所有满足匹配条件的结果,放在列表里。

    import re
    ret = re.findall('[a-z]+', 'eric lucifer yuan')#匹配属于a-z的多个字符
    print(ret)

1.3 RE之search方法

  从前往后,找到一个就返回,返回的变量需要调用group才能拿到结果。如果没有找到,那么返回None,调用group会报错。

    #找到第一个符合要求的就输出
    import re
    ret = re.search('a', 'eric egon yuan')
    if ret:
        print(ret.group())

1.4 RE之match方法

  1.match是从头开始匹配,如果正则规则从头开始可以匹配上,就返回一个变量。
  2.匹配的内容需要用group才能显示。如果没匹配上,就返回None,调用group会报错。

    import re
    ret = re.match('[a-z]+', 'eva egon yuan')
    if ret:
        print(ret.group())

1.5 RE之split方法

    import re
    ret = re.split('[ab]', 'abcd')
    # 先按'a'分割得到''和'bcd',在对''和'bcd'分别按'b'分割
    print(ret)  # ['', '', 'cd']

1.6 RE之sub与subn方法

    import re
    ret = re.sub('\d', 'H', 'eva3egon4yuan4',1)
    #先进行数字匹配,在将数字替换成'H',参数1表示只替换1个
    print(ret) #evaHegon4yuan4

    import re
    ret = re.subn('\d', 'H', 'eva3egon4yuan4')
    #将数字替换成'H',返回元组(替换的结果,替换了多少次)
    print(ret)

1.7 RE之compile方法

  此法可用于多次匹配同一种类型的结果时使用,这样只编译了一次,加快了程序执行速度。

    import re
    obj = re.compile('\d{3}')#匹配数字,重复次数:3次
    #将正则表达式编译成为一个正则表达式对象,规则要匹配的是3个数字
    ret = obj.search('abc123eeee') #正则表达式对象调用search,参数为待匹配的字符串
    print(ret.group())
    ret = obj.search('abcashgjgsdghkash456eeee3wr2') #正则表达式对象调用search,参数为待匹配的字符串
    print(ret.group())  #结果 : 123

1.8 RE之finditer方法

  filter就是将符合正则表达式的存入迭代器,读取时可以通过next(ret).group()进行一个一个读,也可以通过循环一次读完。

    import re
    ret = re.finditer('\d', 'ds3sy4784a')   #finditer返回一个存放匹配结果的迭代器
    print(ret)  # <callable_iterator object at 0x10195f940>
    print(next(ret).group())  #查看第一个结果
    print(next(ret).group())  #查看第二个结果
    print([i.group() for i in ret])  #查看剩余的左右结果
    for i in ret:
        print(i.group())

1.9 复杂正则的使用

  1.9.1 findall

    import re
    ret = re.findall('www.(baidu|oldboy).com', 'www.oldboy.com')
    print(ret)
    # ['oldboy']这是因为findall会优先把匹配结果组里内容返回,如果想要匹配结果,取消权限即可

    import re
    ret = re.findall('www.(?:baidu|oldboy).com', 'www.oldboy.com')
    print(ret)  # ['www.oldboy.com']

  1.9.2 search

    import re
    ret = re.search('^[1-9](\d{14})(\d{2}[0-9x])?$','110105199912122277')
    print(ret.group())
    print(ret.group(1))
    print(ret.group(2))

  1.9.3  split

    import re
    ret=re.split("\d+","eva3egon4yuan")
    print(ret) #结果 : ['eva', 'egon', 'yuan']

    import re
    ret=re.split("(\d+)","eva3egon4yuan")
    print(ret) #结果 : ['eva', '3', 'egon', '4', 'yuan']

  1.9.4 爬虫实例

    import re
    from urllib.request import urlopen

    def getPage(url):
        response = urlopen(url)
        return response.read().decode('utf-8')

    def parsePage(s):
        ret = re.findall(
        '<div class="item">.*?<div class="pic">.*?<em .*?>(?P<id>\d+).*?<span class="title">(?P<title>.*?)</span>'
       '.*?<span class="rating_num" .*?>(?P<rating_num>.*?)</span>.*?<span>(?P<comment_num>.*?)评价</span>',s,re.S)
        return ret

    def main(num):
        url = 'https://movie.douban.com/top250?start=%s&filter=' % num
        response_html = getPage(url)
        ret = parsePage(response_html)
        print(ret)

    count = 0
    for i in range(10):   # 10页
        main(count)
        count += 25

  步骤:

  1> url从网页上把代码搞下来
  2> bytes decode ——> utf-8 网页内容就是我的待匹配字符串
  3> ret = re.findall(正则,带匹配的字符串) #ret是所有匹配到的内容组成的列表

posted on 2019-11-18 23:32  眨眼星舟_Eric  阅读(131)  评论(0编辑  收藏  举报

导航