正则表达式 和 re模块

 
    模块
        三种来源
            1.内置的
            2.第三方
            3.自定义的
        四种表现形式
            1.py文件(******)
            2.共享库
            3.一系列模块文件的结合体>>>:包(******)
            4.C语言编写
        使用模块的好处
            1.提高开发效率
            2.减少代码冗余
            3.项目结构清晰



    谁是执行文件,谁是被导入文件
    import
        import md  文件名带后缀 模块名在导入的时候不要加后缀
        首次导入
            先创建执行文件名称空间

            1.创建md.py文件名称空间
            2.运行md.py文件内的代码,将产生的名字放到md.py文件的名称空间中
            3.在执行文件中拿到一个md执行md.py的名称空间

            import句式访问模块名称空间中的名字固定写法:模块名.名字
            md.name
            好处在于指名道姓的跟某个模块要名字,不会与当前执行文件名字冲突

        知识点补充
            当模块名比较复杂的时候 可以给模块名起别名

        重复导入:不会再执行模块文件 直接沿用首次导入模块的成果


    from...import...
        首次导入
            先创建执行文件名称空间

            1.创建md.py文件名称空间
            2.运行md.py文件内的代码,将产生的名字放到md.py文件的名称空间中
            3.在执行文件中拿到一个名字改名字直接指向md.py名称空间中的某个名字

            from...import...使用模块中的名字,直接写名字就可以访问
            可能会与当前执行文件中的名字冲突
            x = 1
            from md import x
            print(x)  模块md中的x


            from md import x
            x = 1000
            print(x)  当前文件中的x


        知识点补充
            from md import *  不推荐使用 消耗资源过多

            __all__ = ['','','']  当__all__所在的文件被当做模块导入的时候
            ___all__列表写什么 执行导入语句那个文件就能拿到什么
            __all__不写的情况下 默认是将所在文件所有的名字都暴露给导入者


            __name__当__name__所在的文件被当做执行文件执行的时候__name__的值就等于__main__
            当__name__所在的文件被当做模块导入的时候__name__的值就等于模块名(py的文件名 不加后缀)

        if __name__ == '__main__':
            启动代码/测试代码

        pycharm中可以写main+tab自动补全上面的格式
    循环导入
        你导了我 我导了你
        循环导入的问题 在你的程序中应该尽量避免
            1.解决循环导入方式1
                将循环导入的语句放在要导入的名字的语句下方
            2.解决循环导入方式2
                将导入语句写到函数体代码内(利用函数在定义阶段只检测语法不执行代码)
            3.解决循环导入方式3(******)
                将循环导入的名字 放到另外一个文件中
    模块的查找顺序
            1.先在内存中找
            2.内置
            3.system path(程序的环境变量)

                查找模块的路径以执行文件所在的文件夹为准
                demo
                    -dir
                        --md.py
                    -run.py
                第一种导入:基于当前执行文件所在文件夹路径依次往下找
                第二种导入:直接将你需要导入的那个模块所在的文件夹路径添加到system path中

    绝对导入与相对导入
        绝对导入写的就是全路径  该全路径以执行文件所在的文件夹路径为基准
        相对导入
            .代表当前路径
            ..代表上一级路径
            ...代表上上一级路径

            注意相对导入只能在模块文件中使用,执行文件中不能使用相对导入
            一般情况下项目只会有一个执行文件,项目的其他文件其实都是模块
            所以相对导入的应用场景也是很广泛

    软件开发目录规范
        1.项目结构更清晰
        2.便于管理
        3.扩展性高


    项目名
        -bin
            --start.py 项目的启动文件(start.py也可以直接放在项目根目录下)
                import os
                import sys
                将项目名所在的路径添加到system path中,如果你是pycharm打开 pycharm会自动将顶级目录路径添加到system path中
                而一旦你的项目不是用pycharm打开,亦或者是被用户下载到他自己的机器上,你就必须在项目启动之前将路径设置好
                BASE_DIR = os.path.dirname(os.path.dirname(__file__))
                sys.path.append(BASE_DIR)

                from core import src
                if __name__ == '__main__':
                    src.run()
        -conf
            --settings 项目的配置文件
        -core
            --src.py 项目的核心逻辑文件可能不止一个
        -db
            --数据相关的"文件"
        -lib
            --common.py 项目所使用的到的一些公共的功能
        -log
            --项目所有的日志文件(用户的操作,记录,浏览历史...)
        Readme.txt  项目的大致介绍
        start.py (start.py也可以直接放在项目根目录下)
            import os
            import sys
            将项目名所在的路径添加到system path中,如果你是pycharm打开 pycharm会自动将顶级目录路径添加到system path中
            而一旦你的项目不是用pycharm打开,亦或者是被用户下载到他自己的机器上,你就必须在项目启动之前将路径设置好
            BASE_DIR = os.path.dirname(__file__)
            sys.path.append(BASE_DIR)

            from core import src
            if __name__ == '__main__':
                src.run()
模块的回顾

什么是正则表达式?

  正则就是用来筛选字符串中指定的内容 (其实就是一堆字符串你可以通过正则来筛选他)

  应用场景主要包括 爬虫 数据分析

re模块与正则的关系:

  正则表达式不是python独有的 他是一门独立的技术且所有语言都可以使用正则 但是 python如果想使用正则的话必须通过re模块

正则的使用方法 :(想匹配具体的内容 可以直接写完整的内容,不需要写正则)

  基本的方法

   正则的元字符   

      .    匹配除换行符外的字符

     w     匹配字母数字下划线

     s    匹配空格换行符缩进等换行符

     d    匹配数字

     W      匹配除了字母数字下划线的所有字符

     S       匹配除了空格 换行 缩进 的所有字符

     D       匹配除了数字的所有字符

            匹配单词的末尾

             匹配制表符

           匹配换行符

     ^      匹配字符开始吧     

        ^可以和$连用 会精准的限制匹配内容  两者之间写什么 匹配的字符串就必须是什么 多一个不行 绍一个也不行

     $  匹配字符结尾

        a|b   匹配a或者b 要么a 要么b       (使用时需最长的放在里面 短的放在外面 如  adb|ab)

     ()     匹配括号内的表达式 也表示一个组

         正则中分组的操作: 当多个正则符号需要重复多次的时候或者多个正则符号需要当做一个整体来进行其他操作的时候就可以使用分组来把它们括起来

     [ ]     匹配中括号内的字符     (里面的表达式都是或的关系)

             可以这样使用[1-9A-Z]

             这样的话就可以匹配1到9和A-Z啦

     [^   ]  匹配除了中括号内的字符

量词  (量词只能跟在元字符后面 且! 量词只能够限制紧挨着他的那个元字符)

     *   表示 重复0次或重更多次

     + 表示 重复1次 或者重复更多次

     ? 表 重复0次或者重复1次

     {n} 表示重复n次

     {n,}表示重复n次或更多次

     {n,m} 表示重复n次到m次

  在量词当中 * ? + 属于贪婪匹配  且正则在匹配的时候默认都是贪婪匹配   你可以通过在量词后加一个?号 此时的贪婪匹配就转化成惰性匹配也叫 非贪婪匹配

re模块的使用:

    可以使用一个例子来体现出正则的好处 例如我需要判断用户的输入 是不是一一个手机号 需要判断开头个数] 

while True:
    phone_number=input('please input your phone number')
    if len(phone_number) == 11 
        and phone_number.isdigit()
        or phone_number.startswith('12)
        or phone_number.startswith('13)
        or phone_number.startswith('15)
        or phone_number.startswith('17)
        or phone_number.startswith('18):
        pritn("合法手机号")
     else:
        print("非法手机号")

那么我们使用re模块的话怎么改呢

# 先导入模块
import re
phone_number=input('please input your phone number')
if re.match('^12|13|15|17|18[0-9]{9}$',phone_number)
  print('合法手机')
else:
  print('不合法手机')

方法的介绍

findall()  使用方法  re.findall(正则表达式,字符内容)

findall 方法可以一次性把全部的a都找出来 但是返回的值是一个列表  如果查找不存在 他会返回一个空列表

search 方法也是用re.search(正则表达式 匹配字符串)

发现返回了一个地址(对象)  search他不会给你返回结果而是给你返回一个对象  需要使用一个叫group的方法来看匹配到的结果 

 group() 使用方法 在你re模块赋值的那个变量后加.group()

但是我们会发现他只会返回一次a 注意 :1.sear只会正则查找一次 只要查到了结果 就不会往后边查找了  2.当查找不存在的情况下 调用group直接报错  查找不存在的时候他会给你返回一个None 

match 方法(正则表达式,匹配字符)

我们发现match方法呢查找a 字符串中有a但是给我们返回了一个NONE 因为 match只会匹配字符开头部分 当字符开头不符合的情况下 返回的也是None 同时也可以调用group 但是是none会报错

re.spilt() 

ret = re.split('[ab]', 'abcd') 
>>>['', '', 'cd'] 
# 返回的还是列表
 # 先按'a'分割得到''和'bcd',在对''和'bcd'分别按'b'分割

re.sub()

import re
res=re.sub('d','L','WDADs123jdhawuyasu')
print(res)

>>>WDADsLLLjdhawuyasu

将数字替换成L sub(替换的字符,新的内容,字符内容)(相当于字符的replace)

ret = re.sub('d', 'H', 'eva3egon4yuan4',1)
print(ret)

>>>evaHegon4yuan4
先按照正则表达式查找所有符合该表达式的内容 统一替换成'新的内容'  还可以通过n来控制替换的个数
ret = re.subn('d', 'H', 'eva3egon4yuan4')
# 将数字替换成'H',返回元组(替换的结果,替换了多少次)
ret1 = re.subn('d', 'H', 'eva3egon4yuan4',1)
# 将数字替换成'H',返回元组(替换的结果,替换了多少次)
print(ret)  # 返回的是一个元组 元组的第二个元素代表的是替换的个数

>>>('evaHegonHyuanH', 3)

re.compile

obj = re.compile('d{3}')  
#将正则表达式编译成为一个 正则表达式对象,规则要匹配的是3个数字
ret = obj.search('abc123eeee') 
#正则表达式对象调用search,参数为待匹配的字符串
res1 = obj.findall('347982734729349827384')
print(ret.group())  
#结果 : 123
print(res1) 
#结果 : ['347', '982', '734', '729', '349', '827', '384']

re.finditer()

import re
ret = re.finditer('d', 'ds3sy4784a')   
#finditer返回一个存放匹配结果的迭代器
print(ret)  # <callable_iterator object at 0x10195f940>
print(next(ret).group())  # 等价于ret.__next__()
print(next(ret).group())  # 等价于ret.__next__()
print(next(ret).group())  # 等价于ret.__next__()
print(next(ret).group())  # 等价于ret.__next__()
print(next(ret).group())  # 等价于ret.__next__()
print(next(ret).group())  # 等价于ret.__next__()   查出迭代取值的范围 直接报错
print(next(ret).group())  #查看第一个结果
print(next(ret).group())  #查看第二个结果
print([i.group() for i in ret])  #查看剩余的左右结果

()组在 search findall match 的用法

res = re.search('^[1-9](d{14})(d{2}[0-9x])?$','110105199812067023')
还可以给某一个正则表达式起别名
res = re.search('^[1-9](?P<password>d{14})(?P<username>d{2}[0-9x])?$','110105199812067023')
print(res.group())
print(res.group('password'))
print(res.group(1))
print(res.group('username'))
print(res.group(2))
print(res.group(2))
print(res.group(1))



ret1 = re.findall('www.(baidu|oldboy).com', 'www.oldboy.com')
ret2 = re.findall('www.(?:baidu|oldboy).com', 'www.oldboy.com')  # 忽略分组优先的机制
print(ret1,ret2)  # ['oldboy']     这是因为findall会优先把匹配结果组里内容返回,如果想要匹配结果,取消权限即可



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

ret1=re.split("(d+)","eva3egon4yuan")
print(ret1) #结果 : ['eva', '3', 'egon', '4', 'yuan']
趁自己还没死 多折腾折腾
原文地址:https://www.cnblogs.com/lddragon/p/11203318.html