美文网首页
Python 正则表达式

Python 正则表达式

作者: PythonMaO | 来源:发表于2017-06-17 13:56 被阅读344次

    正则表达式

    1. 正则表达式概述

    • 正则表达式,又称正规表示式、正规表示法、正规表达式、规则表达式、常规表示法(英语:Regular Expression,在代码中常简写为regex、regexp或RE),是计算机科学的一个概念。正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串。在很多文本编辑器里,正则表达式通常被用来检索、替换那些匹配某个模式的文本。
    • Regular Expression的“Regular”一般被译为“正则”、“正规”、“常规”。此处的“Regular”即是“规则”、“规律”的意思,Regular Expression即“描述某种规则的表达式”之意。

    2. 模块操作

    在Python中需要通过正则表达式对字符串进行匹配的时候,可以使用一个模块,名字为re
    2.1 re模块的使用过程

      # 导入re模块
    import re
    
    # 使用match方法进行匹配操作
    result = re.match(正则表达式,要匹配的字符串)
    
    # 如果上一步匹配到数据的话,可以使用group方法来提取数据
    result.group()
    
    • **re.match **

    查询标志

    大部分查询方法还可以接受一个查询标志参数。查询标志让正则表达式具有不同的行为。下面一一说明。

    标志 作用
    re.A、
    re.ASCII
    以ASCII模式查询,默认是Unicode模式
    re.DEBUG 显示编译表达式的调试信息
    re.I、re.IGNORECASE 忽略字母的大小写
    re.L、re.LOCALE 以区域敏感方式查询匹配
    re.M、re.MULTILINE 开启多行模式,开启之后行边界符^$会匹配每行的开始和结束,而不是整个字符串的开始和结束
    re.S、re.DOTALL 使用此标志,会让点符号匹配所有字符,默认情况下点符号会匹配换行符以外的符号
    re.X、re.VERBOSE 开启啰嗦模式,可以在写正则表达式的时候添加注释

    re.match是用来进行正则匹配检查的方法,若字符串匹配正则表达式,则match方法返回匹配对象(Match Object),否则返回None(注意不是空字符串"")。
    匹配对象Macth Object具有group方法,用来返回字符串的匹配部分。

    2.2re模块示例(匹配以taobao开头的语句)

    >>>import re
    >>>re.match('taobao', 'taobao.com')
    <_sre.SRE_Match object; span=(0, 6), match='taobao'>
    >>>re.match('taobao', 'taobao.com').group()
    'taobao'
    

    说明

    • re.match() 能够匹配出以xxx开头的字符串,是从第一个字符开始匹配的

    3. 表示字符

    字符 功能
    中文 [\u4e00-\u9fa5]
    . 匹配任意一个字符(除了\n)
    [ ] 匹配[ ]中列举的一个字符
    \d 匹配数字,即0-9
    \D 匹配非数字,即不是数字
    \s 匹配空白,即空格,tab键
    \S 匹配非空白
    \w 匹配单词字符,即a-z、A-Z、0-9、_,还有各个国家的文字
    \W 匹配非单词字符
    • .匹配任意一个字符(除了\n)
    >>>import re
    >>>re.match('.','abc')
    <_sre.SRE_Match object; span=(0, 1), match='a'>
    >>>re.match('.','abc').group()
    'a'
    >>>re.match('.','\nabc')
    >>>re.match('.','\tabc')
    <_sre.SRE_Match object; span=(0, 1), match='\t'>
    >>>re.match('.','\tabc').group()
    '\t'
    

    匹配[ ]中列举的一个字符

    >>>import re
    >>>re.match("[hH]","hello Python")
    <_sre.SRE_Match object; span=(0, 1), match='h'>
    >>>re.match("[hH]","Hello Python")
    <_sre.SRE_Match object; span=(0, 1), match='H'>
    >>>re.match("[0-9]","7Hello Python")
    <_sre.SRE_Match object; span=(0, 1), match='7'>
    
    

    \w 匹配单词字符,即a-z、A-Z、0-9、_,还有各个国家的文字。加上第三个参数re.ASCII就是以ASCII码匹配,就只能匹配字母、数字、下划线

    >>>import re
    >>>re.match('\w','かきく')
    <_sre.SRE_Match object; span=(0, 1), match='か'>
    >>>re.match('\w','ㅈㅊㅅ')
    <_sre.SRE_Match object; span=(0, 1), match='ㅈ'>
    >>>re.match('\w','汉字')
    <_sre.SRE_Match object; span=(0, 1), match='汉'>
    >>>re.match('\w','abc')
    <_sre.SRE_Match object; span=(0, 1), match='a'>
    >>>re.match('\w','汉字',re.ASCII)#这个就没有匹配成功
    >>>re.match('\w','a汉字',re.ASCII)
    <_sre.SRE_Match object; span=(0, 1), match='a'>
    

    4. 原始字符串

    在很多编程语言中,由于有转义字符这么一种东西的存在,导致正则表达式需要使用两个斜杠来处理。

    • Python中字符串前面加上 r 表示原生字符串,
    • 与大多数编程语言相同,正则表达式里使用""作为转义字符,这就可能造成反斜杠困扰。假如你需要匹配文本中的字符"",那么使用编程语言表示的正则表达式里将需要4个反斜杠 "\" :前 两个和后两个分别用于在编程语言里转义成反斜杠,转换成两个反斜杠后再在正则表达式里转义成一个反斜杠。
    • Python里的原生字符串很好地解决了这个问题,有了原始字符串,你再也不用担心是不是漏写了反斜杠,写出来的表达式也更直观。
    >>>import re
    >>>m = "c:\\a\\b\\c"
    >>>m
    'c:\\a\\b\\c'
    >>>print(m)
    c:\a\b\c
    >>>re.match("c:\\\\",m).group()
    'c:\\'
    >>>print(re.match("c:\\\\",m).group())
    c:\
    >>>re.match(r"c:\\a",m).group()
    'c:\\a'
    >>>print(re.match(r"c:\\a",m).group())
    c:\a
    

    5. 表示数量

    匹配多个字符的相关格式

    字符 功能
    * 匹配前面的子表达式任意次,即可有可无
    + 匹配前一个字符出现1次或者无限次,即最少有一次
    ? 匹配前一个字符出现1次或者0次,即要么有1次,要么没有
    {m} 匹配前一个字符出现m次
    {m,} 匹配前一个字符至少出现m 次
    {m,n} 匹配前一个字符出现从m到n次

    示例1 *
    匹配出,一个字符串第一个字母为大小字符,后面都是小写字母并且这些小写字母可有可无

    >>>import re
    >>>re.match("[A-Z][a-z]*","Aabcdef")
    <_sre.SRE_Match object; span=(0, 7), match='Aabcdef'>
    

    示例2:?
    需求:匹配出,0到99之间的数字

    >>>import re
    re.match("[1-9]?[0-9]","33")
    >>><_sre.SRE_Match object; span=(0, 2), match='33'>
    >>>re.match("[1-9]?[0-9]","09")
    <_sre.SRE_Match object; span=(0, 1), match='0'>
    >>>re.match("[1-9]?[0-9]","9")
    <_sre.SRE_Match object; span=(0, 1), match='9'>
    

    示例3:{m,n}
    需求:匹配出,8到20位的密码,可以是大小写英文字母、数字、下划线

    >>>import re
    >>>re.match("[a-zA-Z0-9_]{8,20}","1ad12f23s34455ff66")
    <_sre.SRE_Match object; span=(0, 18), match='1ad12f23s34455ff66'>
    

    示例4:
    匹配出163的邮箱地址,且@符号之前有4到20位,例如hello@163.com

    import re
    print('6~18个字符,可使用字母、数字、下划线,需以字母开头')
    while True:
        address=input('>>>输入邮箱地址:')
        ret=re.match('[a-zA-Z]\w{3,19}@163\.com',address)
        if ret == None:
            print('输入有误,请重新输入。邮箱格式为6~18个字符,可使用字母、数字、下划线,需以字母开头')
            continue
        else:
            ret = ret.group()
            print('您的邮箱地址:%s'%ret)
            break
    

    运行结果

    G:\tools\python3.5\python.exe E:/workspace/day29/练习1.py
    6~18个字符,可使用字母、数字、下划线,需以字母开头
    >>>输入邮箱地址:haha
    输入有误,请重新输入。邮箱格式为6~18个字符,可使用字母、数字、下划线,需以字母开头
    >>>输入邮箱地址:haha@163.com
    您的邮箱地址:haha@163.com
    

    6. 表示边界

    字符 功能
    ^ 匹配字符串的开头
    $ 匹配字符串的末尾
    \b 匹配一个单词的边界
    \B 匹配非单词边界

    示例 $

    >>>import re
    >>>re.match("[\w]{4,20}@163\.com", "xiaoWang@163.comheihei")
    <_sre.SRE_Match object; span=(0, 16), match='xiaoWang@163.com'>
    >>>re.match("[\w]{4,20}@163\.com$", "xiaoWang@163.comheihei")
    >>>re.match("[\w]{4,20}@163\.com", "xiaoWang@163.comheihei")
    <_sre.SRE_Match object; span=(0, 16), match='xiaoWang@163.com'>
    
    

    7. 匹配分组

    字符 功能
    | 匹配左右任意一个表达式
    (ab) 将括号中字符作为一个分组
    \num 引用分组num匹配到的字符串
    (?P<name>) 分组起别名
    (?P=name) 引用别名为name分组匹配到的字符串

    示例 |

    >>>import re
    >>>re.match("\w{4,20}@(163|126|qq)\.com", "test@gmail.com")
    >>>re.match("\w{4,20}@(163|126|qq)\.com", "test@qq.com")
    <_sre.SRE_Match object; span=(0, 11), match='test@qq.com'>
    >>>re.match("\w{4,20}@(163|126|qq)\.com", "test@qq.com").group(1)
    'qq'
    

    示例 \number

    >>>import re
    >>>re.match(r"<(\w*)><(\w*)>.*</\2></\1>", "<html><h1>www.taobao.com</h1></html>")
    <_sre.SRE_Match object; span=(0, 36), match='<html><h1>www.taobao.com</h1></html>'>
    >>>re.match(r"<(\w*)><(\w*)>.*</\2></\1>", "<html><h1>www.taobao.com</h2></html>")
    

    第二个匹配不到是后面的\2引用了分组2的值(h1),与字符串中的‘h2’不匹配,所以返回None

    示例:(?P<name>) (?P=name)

    >>>import re
    >>>re.match(r"<(?P<name1>\w*)><(?P<name2>\w*)>.*</(?P=name2)></(?P=name1)>", "<html><h1>www.taobao.com</h1></html>")
    <_sre.SRE_Match object; span=(0, 36), match='<html><h1>www.taobao.com</h1></html>'>
    >>>re.match(r"<(?P<name1>\w*)><(?P<name2>\w*)>.*</(?P=name2)></(?P=name1)>", "<html><h1>www.taobao.com</h2></html>")
    

    注意:
    (?P<name>)和(?P=name)中的字母p大写

    8. re模块的高级用法

    1.search()
    我们在前面提到过match()方法是从字符串的开头开始匹配,一旦开头不匹配,那么整个匹配就失败了。

    import re
    
    s='Hello World 123abc456'
    result=re.match('World.*abc',s)
    print(result)
    result=re.search('World.*abc',s)
    print(result)
    

    运行结果

    None
    <_sre.SRE_Match object; span=(6, 18), match='World 123abc'>
    

    在这里我们有一个字符串,它是以Hello开头的,但是正则表达式我们是以World开头的,整个正则表达式是字符串的一部分,但是这样匹配是失败的,也就是说只要第一个字符不匹配整个匹配就不能成功。

    所以match()方法在我们在使用的时候需要考虑到开头的内容,所以在做匹配的时候并不那么方便,它适合来检测某个字符串是否符合某个正则表达式的规则。
     
     在这里就有另外一个方法search(),它在匹配时会扫描整个字符串,然后返回第一个成功匹配的结果,也就是说,正则表达式可以是字符串的一部分,在匹配时,search()方法会依次扫描字符串,直到找到第一个符合规则的字符串,然后返回匹配内容,如果搜索完了还没有找到,那就返回None。

    我们把上面的代码中的match()方法修改成search(),这样就得到了匹配结果。所以说,为了匹配方便,我们可以尽量使用search()方法。

    2.findall()
      在前面我们说了search()方法的用法,它可以返回匹配正则表达式的第一个内容,但是如果我们想要获取匹配正则表达式的所有内容的话怎么办?这时就需要借助于findall()方法了。

    findall()方法会搜索整个字符串然后返回匹配正则表达式的所有内容。

    3.sub()
    正则表达式除了提取信息,我们有时候还需要借助于它来修改文本,比如我们想要把一串文本中的所有数字都去掉,如果我们只用字符串的replace()方法那就太繁琐了,在这里我们就可以借助于sub()方法。

    示例
    将匹配到的数字加1

    import re
    
    ret = re.sub(r"\d+", '998', "python = 997")
    print(ret)
    
    import re
    
    
    def add(temp):
        strNum = temp.group()
        num = int(strNum) + 1
        return str(num)
    
    
    ret = re.sub(r"\d+", add, "python = 997")
    print(ret)
    
    ret = re.sub(r"\d+", add, "python = 99")
    print(ret)
    

    运行结果

    python = 998
    python = 100
    

    可以传一个函数进去

    4.split()
    根据匹配进行切割字符串,并返回一个列表
    切割字符串“info:xiaoZhang 33 shandong”

    >>>import re
    >>>re.split(r":| ","info:xiaoZhang 33 shandong")
    ['info', 'xiaoZhang', '33', 'shandong']
    

    5.compile()
      前面我们所讲的方法都是用来处理字符串的方法,最后再介绍一个compile()方法,这个方法可以讲正则字符串编译成正则表达式对象,以便于在后面的匹配中复用。
    例如这里有三个日期,我们想分别将三个日期中的时间去掉,所以在这里我们可以借助于sub()方法,sub()方法的第一个参数是正则表达式,但是这里我们没有必要重复写三个同样的正则表达式,所以可以借助于compile()函数将正则表达式编译成一个正则表达式对象,以便复用。
    示例

    import re
    time1='2017-6-15 11:30'
    time2='2017-6-16 12:30'
    time3='2017-6-17 11:30'
    pattern = re.compile('\d{2}:\d{2}')
    result1 = re.sub(pattern,'',time1)
    result2 = re.sub(pattern,'',time2)
    result3 = re.sub(pattern,'',time3)
    print(result1)
    print(result2)
    print(result3)
    

    运行结果

    2017-6-15 
    2017-6-16 
    2017-6-17 
    

    另外compile()还可以传入修饰符,例如re.S等修饰符,这样在search()、findall()等方法中就不需要额外传了。所以compile()方法可以说是给正则表达式做了一层封装,以便于我们更好地复用。

    9. 贪婪和非贪婪

    Python里数量词默认是贪婪的(在少数语言里也可能是默认非贪婪),总是尝试匹配尽可能多的字符;
    非贪婪则相反,总是尝试匹配尽可能少的字符。
    "*","?","+","{m,n}"后面加上,使贪婪变成非贪婪。
    练习代码

    import re
    s = "This is a number 234-235-22-423"
    r1 = re.match("(.+)(\d+-\d+-\d+-\d+)", s)
    print('r1...')
    print(r1.groups())
    
    r2 = re.match("(.+?)(.*?)(\d+-\d+-\d+-\d+?)", s)
    print('r2...')
    print(r2.groups())
    
    r3 = re.match("(.+)(.+?)(\d+-\d+-\d+-\d+?)", s)
    print('r3...')
    print(r3.groups())
    
    r4 = re.match("(.+)(.*?)(\d+?)(-\d+-\d+-\d+?)", s)
    print('r4...')
    print(r4.groups())
    r5 = re.match("(.+?)(.*)(\d+?)(-\d+-\d+-\d+?)", s)
    print('r5...')
    print(r5.groups())
    

    分析一波代码
    r1(.+) + 匹配前一个字符出现1次或者无限次,即最少有一次 从第一个开始匹配,并贪婪的尽可能多的匹配,将23也匹配上,给下一个(\d+)留一个4,因为(\d+)至少匹配一个
    r2 (.+?)从第一个开始匹配,并 非贪婪的匹配到一个T(.*?)接着上个表达式继续匹配,匹配到2的时候发现(\d+-\d+-\d+-\d+?)符合匹配,就结束匹配得到自己的his is a number
    r4 (.+)贪婪的匹配,发现下一个正则表达式(.*)可有可无,于是就接着匹配到(\d+?) 然后(.*)这个组就是空。
    运行结果

    r1...
    ('This is a number 23', '4-235-22-423')
    r2...
    ('T', 'his is a number ', '234-235-22-4')
    r3...
    ('This is a number 2', '3', '4-235-22-4')
    r4...
    ('This is a number 23', '', '4', '-235-22-4')
    r5...
    ('T', 'his is a number 23', '4', '-235-22-4')
    

    10. 练习

    一、从下面的字符串中取出文本(将标签去掉)

    import re
    s= '''<div>
            <p>岗位职责:</p>
    <p>完成推荐算法、数据统计、接口、后台等服务器端相关工作</p>
    <p><br></p>
    <p>必备要求:</p>
    <p>良好的自我驱动力和职业素养,工作积极主动、结果导向</p>
    <p>&nbsp;<br></p>
    <p>技术要求:</p>
    <p>1、一年以上 Python 开发经验,掌握面向对象分析和设计,了解设计模式</p>
    <p>2、掌握HTTP协议,熟悉MVC、MVVM等概念以及相关WEB开发框架</p>
    <p>3、掌握关系数据库开发设计,掌握 SQL,熟练使用 MySQL/PostgreSQL 中的一种<br></p>
    <p>4、掌握NoSQL、MQ,熟练使用对应技术解决方案</p>
    <p>5、熟悉 Javascript/CSS/HTML5,JQuery、React、Vue.js</p>
    <p>&nbsp;<br></p>
    <p>加分项:</p>
    <p>大数据,数理统计,机器学习,sklearn,高性能,大并发。</p>
    
            </div>'''
    a=re.sub('</?p>|</?div>|<br>| ','',s)
    print(a)
    

    运行结果

    
    岗位职责:
    完成推荐算法、数据统计、接口、后台等服务器端相关工作
    
    必备要求:
    良好的自我驱动力和职业素养,工作积极主动、结果导向
    &nbsp;
    技术要求:
    1、一年以上Python开发经验,掌握面向对象分析和设计,了解设计模式
    2、掌握HTTP协议,熟悉MVC、MVVM等概念以及相关WEB开发框架
    3、掌握关系数据库开发设计,掌握SQL,熟练使用MySQL/PostgreSQL中的一种
    4、掌握NoSQL、MQ,熟练使用对应技术解决方案
    5、熟悉Javascript/CSS/HTML5,JQuery、React、Vue.js
    &nbsp;
    加分项:
    大数据,数理统计,机器学习,sklearn,高性能,大并发。
    

    相关文章

      网友评论

          本文标题:Python 正则表达式

          本文链接:https://www.haomeiwen.com/subject/bwvmqxtx.html