• Python之路【第07章】:Python文件操作(文件,正则)


    Python文件操作(文件,正则)

    • 文件:

    • 文件操作

    • 文件编码

    • 打开文件的几种模式

    • 操作文件的方法

    • 文件内光标的移动

    • 文件的修改

    • 正则:

    一、文件的操作

    1.文件的介绍:

      计算机系统分为:计算机 硬件、操作系统、应用程序三部分;

      无论使用python还是其他语言若想要把数据永久的保存下来,必须要将存在内存中的数据刷新到硬盘中,这就涉及到应用程序要操作硬件;我们知道,应用程序是不能直接操作硬件的,只能通过操作系统来调用硬件,操作系统把复杂的硬件操作封装成简单的接口给用户/应用程序使用,其中文件就是操作系统提供给应用程序老操作硬盘虚拟概念,用户或应用程序通过操作文件,可以将自己的数据永久保存下来。

    2.操作文件的流程:

      有了文件的概念,我们无需在去考虑操作硬盘的细节,只需要关注操作文件的流程:

    1 1.打开文件,得到文件句柄并赋值给一个变量;
    2 2.通过文件句柄对文件进行一系列的操作;
    3 3.关闭文件;

    3.在python中的表示:

    #1.打开文件,得到文件句柄并赋值给一个变量;
    f = open("python.txt","r",encoding="utf-8")
    ## 注意,默认打开模式就是r只读模式;
    
    
    #2.通过文件句柄对文件进行操作:
    date = f.read()
    
    
    #3.关闭文件
    f.close()

    4.“f = open("python.txt","r",encoding="utf-8")”的过程分析

    #1.由应用程序向操作系统发起系统调用open(...)
    
    #2.操作系统打开该文件,并返回一个文件句柄给应用程序
    
    #3.应用程序将文件句柄复制给变量f

    5.关于文件操作需要注意的地方,关于文件操作需要注意的地方,关于文件操作需要注意的地方,重要的事敲三遍;

    #强调第一点:
    
        打开一个文件包含两部分资源:操作系统级打开的文件 + 应用程序的变量;在操作完毕一个文件时,必须把与该文件的这两部分资源一个不落的回收;
        
        回收方法:
        1.f.close()    #回收操作系统级打开的文件;
        2.del f         #回收应用程序级的变量;
        
        其中 del f 一定要发生在f.close() 之后,否则就会导致操作系统打开的文件还没有关闭,白白占用资源;而python自动的垃圾回收机制决定了我们无需考虑 del f ,这就要求我们在操作完毕文件后,一定要记得 f.close()
    
        还有一种方法,不用我们去考虑f.close()问题,那就是使用with关键字来帮我们管理上下文:
    with open('a.txt','w') as f:
        pass
    
    with open('a.txt','r') as read_f,open('b.txt','w') as write_f:
        data=read_f.read()
        write_f.write(data)
    #强调第二点:
    
        f=open(...)是由操作系统打开文件,那么如果我们没有为open指定编码,那么打开文件的默认编码很明显是操作系统说了算了,操作系统会用自己的默认编码去打开文件,在windows下是gbk,在linux下是utf-8。
    
        这就用到了上节课讲的字符编码的知识:若要保证不乱码,文件以什么方式存的,就要以什么方式打开。

    6.py2和py3中的file和open:

      首先在python3中操作文件只有一种选择,那就是open();

      而在python2中则有两种方式:file()与open();

      两者都能够打开文件,对文件进行操作,也具有相似的用法和参数,但是,这两种文件打开方式有本质的区别,file为文件类,用file()来打开文件,相当于这是在构造文件类,而用open()打开文件,是用python的内建函数来操作,我们一般使用open()打开文件进行操作,而用file当做一个类型,比如type(f) is file;

    7.文件路径:

      绝对路径:从硬盘的根目录开始查找,或者从互联网上寻找一个路径;

      相对路径:相对于当前程序所在的文件夹

    二、文件编码

      上面提过,重要的事在说一遍;

      f=open(...)是由操作系统打开文件,那么如果我们没有为open指定编码,那么打开文件的默认编码很明显是操作系统说了算了,操作系统会用自己的默认编码去打开文件,在windows下是gbk,在linux下是utf-8。

    三、打开文件的几种模式

      语法:文件句柄(变量) = open(file, mode='r', buffering=None, encoding=None, errors=None, newline=None, closefd=True)

      模式mode:

    #1.打开文件的模式有(默认为文本模式):
        模式                          说明
        r              只读模式,也是默认模式,文件必须存在,不存在则跑出异常;
        w              只写模式,不可读;不存在则创建,存在的话如果有进行写入动作则清空文件内容并写入新内容,如果没有写入动作则只打开不清空文件;
        a              只追加模式,不可读,不存在则创建,存在则只在末尾追加内容;

    #例子:
      对"python.txt"这个文件里的内容进行读取;

        [root@wolaixunshan ~]# echo "人生苦短,python当歌" > /tmp/python.txt
        [root@wolaixunshan ~]# cat py1.py
        #!/usr/bin/python3
        #-*- coding:UTF-8 -*-
        #Author:zjk
        #mail:zjkmmd@163.com
        #Time:2018-08-06 15:05:32
        #Name:py1.py
        #Version:V1.0
        #Description:This is a script.
        f = open("/tmp/python.txt","r",encoding="utf-8")
        date = f.read()
        print(date)
        f.close()

        [root@wolaixunshan ~]# python3 py1.py 

        人生苦短,python当歌



    #2.对于非文本文件,只能使用b模式打开,"b"表示以字节的方式操作(而所有文件也都是以字节的形式存储的,使用这种模式无需考虑文本文件的字符编码、
    图片文件的jpg格式、视频文件的avi格式)
    模式 说明 rb 只读模式,文件必须存在,不存在则抛出异常; wb 只写模式,不存在则创建,存在的话如果有写操作则清空文件内容并将写操作数据加入进行,没有写操作的话则不清空文件; ab 只追加模式,不可读,不存在则创建,存在则只追加内容;

    注意:以b方式打开时,读取到的内容是字节类型,写入时也许要提供字节类型,不能指定编码;
    #3."+"模式,就是增加了一个功能;
        模式                        说明
        r+                读写(可读,可写)
        w+                写读(可写,可读)
        a+                写读(可写,可读)
    
    注意:
        1.r+模式:
        读写模式,先读后写;这里需要注意的时,在r+模式中无论读取了多少内容,光标在哪里,写入的时候都是在结尾写入的,除非上来就写入,
       这时的写入是写在文件开头的 例如: 使用r
    +模式先读取3个字符内容,然后进行数据添加; [root@wolaixunshan ~]# cat /tmp/python.txt ABCDEFG HIJKLMN OPQRST UVWXYZ [root@wolaixunshan ~]# cat py1.py #!/usr/bin/python3 #-*- coding:UTF-8 -*- #Author:zjk #mail:zjkmmd@163.com #Time:2018-08-06 15:05:32 #Name:py1.py #Version:V1.0 #Description:This is a script. f = open("/tmp/python.txt","r+",encoding="utf-8") date = f.read(3) f.write("老铁666") print(date) f.close() [root@wolaixunshan ~]# python3 py1.py ABC [root@wolaixunshan ~]# cat /tmp/python.txt ABCDEFG HIJKLMN OPQRST UVWXYZ 老铁666[root@wolaixunshan ~]# ##会发现数据是加到末尾了并不是光标的所在处!这点需要注意
    #4.以bytes类型操作的读写、写读、追加写读模式
        模式                说明
        r+b            读写,可读,可写
        w+b            写读,可写,可读
        a+b            追加写读,可写,可读

    四、操作文件的方法

      常用的函数:

      1.file.close()

      说明:用于关闭一个已打开的文件。关闭后的文件不能再进行读写操作, 否则会触发 ValueError 错误。 close() 方法允许调用多次。当 file 对象,被引用到操作另外一个文件时,Python 会自动关闭之前的 file 对象。 使用 close() 方法关闭文件是一个好的习惯。

      语法:file。close()

      实例:

    #打开文件
    f = open("python.txt", "wb")
    print("文件名为: ", f.name)
    
    #关闭文件
    f.close()

      

      2.file.flush()

      说明:用来刷新缓冲区的,即将缓冲区中的数据立刻写入文件,同时清空缓冲区,不需要是被动的等待输出缓冲区写入。一般情况下,文件关闭后会自动刷新缓冲区,但有时你需要在关闭前刷新它,这时就可以使用 flush() 方法。

      语法:file.flush()

      实例:

    #打开文件
    f = open("python.txt", "wb")
    print("文件名为: ", f.name)
    
    #刷新缓冲区数据到磁盘
    f.flush()
    
    #关闭文件
    f.close()

      3.file.read(size)

      说明:用于从文件读取指定的字符数,如果未给定或为负则读取所有。如果使用的是rb模式,则读取出来的是size个字节

      参数:size -------> 指定从文件读取的字符数或字节数;

      返回值:返回从字符串中读取的字符或字节;

      实例:

    [root@wolaixunshan ~]# cat /tmp/python.txt 
    张鋆康
    ABCDEFG
    HIJKLMN
    OPQRST
    UVWXYZ
    [root@wolaixunshan ~]# cat py1.py 
    #!/usr/bin/python3
    #-*- coding:UTF-8 -*-
    f = open("/tmp/python.txt","r",encoding="utf-8")
    date = f.read(1)
    print(date)
    f.close()
    [root@wolaixunshan ~]# python3 py1.py 
    张
    [root@wolaixunshan ~]# cat py1.py
    #!/usr/bin/python3
    #-*- coding:UTF-8 -*-
    f = open("/tmp/python.txt","rb")
    date = f.read(3)
    print(date)
    f.close()
    [root@wolaixunshan ~]# python3 py1.py 
    b'xe5xbcxa0'
    >>> s = b'xe5xbcxa0'
    >>> print(s.decode("UTF-8"))
    张

      

      4.file.fileno()

      说明:返回一个整型的文件描述符(file descriptor FD 整型),可用于底层操作系统的 I/O 操作

      语法:file.fileno()

      返回值:返回文件描述符。

      实例:

    [root@wolaixunshan ~]# cat py1.py 
    #!/usr/bin/python3
    #-*- coding:UTF-8 -*-
    f = open("/tmp/python.txt","rb")
    print("文件名为:",f.name)
    fid = f.fileno()
    print("文件描述符:",fid)
    f.close()
    [root@wolaixunshan ~]# python3 py1.py 
    文件名为: /tmp/python.txt
    文件描述符: 3

      5.file.isatty()

      说明:检测文件是否连接到一个终端设备,如果是返回 True,否则返回 False;

      语法:file.isatty

      返回值:如果连接到一个终端设备返回 True,否则返回 False;

      实例:

    [root@wolaixunshan ~]# cat py1.py
    #!/usr/bin/python3
    #-*- coding:UTF-8 -*-
    f = open("/tmp/python.txt","rb")
    print("文件名为:",f.name)
    ret = f.isatty()
    print("返回值:",ret)
    f.close()
    [root@wolaixunshan ~]# python3 py1.py 
    文件名为: /tmp/python.txt
    返回值: False

      6.file.readline(size)

      说明:用于从文件读取整行,包括 " " 字符。如果指定了一个非负数的参数,则返回指定大小的字节数,包括 " " 字符;

      语法:file.readline(size)

      参数:size ----------> 从文件中读取的字节数或字符数;如果是rb模式就是读取的字节,如果是普通模式就是读取的字符;

      返回值:返回从字符串中读取的字节或字符;

      实例:

    [root@wolaixunshan ~]# cat /tmp/python.txt 
    张鋆康
    ABCDEFG
    HIJKLMN
    OPQRST
    UVWXYZ
    [root@wolaixunshan ~]# cat py1.py 
    #!/usr/bin/python3
    #-*- coding:UTF-8 -*-
    f = open("/tmp/python.txt","r")
    print("文件名为:",f.name)
    line = f.readline().strip()
    print("读取一行:",line)
    ret = f.readline(4)
    print("读取4个字符:",ret)
    f.close()
    [root@wolaixunshan ~]# python3 py1.py 
    文件名为: /tmp/python.txt
    读取一行: 张鋆康
    读取4个字符: ABCD

      7.file.readlines()

      说明:用于读取所有行(直到结束符 EOF)并返回列表,该列表可以由 Python 的 for... in ... 结构进行处理。 如果碰到结束符 EOF 则返回空字符串;

      语法:file.readlines()

      返回值:返回列表,包含所有的行;

      实例:

    [root@wolaixunshan ~]# cat /tmp/python.txt 
    张鋆康
    ABCDEFG
    HIJKLMN
    OPQRST
    UVWXYZ
    [root@wolaixunshan ~]# vim py1.py 
    #!/usr/bin/python3
    #-*- coding:UTF-8 -*-
    f = open("/tmp/python.txt","r")
    print("文件名为:",f.name)
    line = f.readlines()
    print("读取全部行:",line)                                                                    
    f.close()
    [root@wolaixunshan ~]# python3 py1.py 
    文件名为: /tmp/python.txt
    读取全部行: ['张鋆康
    ', 'ABCDEFG
    ', 'HIJKLMN
    ', 'OPQRST
    ', 'UVWXYZ
    ']

      8.seek(self, offset: int, whence: int = 0)

      说明:用于移动文件读取指针到指定位置。

      语法:file.seek( offset: int, whence: int = 0)

      参数:offset -----------> 开始的偏移量,也就是代表需要移动偏移的字节数,正数表示向右偏移,负数表示向左偏移;

         whence --------> 可选,默认值为0,给offset参数一个定义,表示要从哪个位置开始偏移;0代表从文件开头开始算起,1代表从当前位置开始算起,2代表从文件末尾算起

      实例:

    [root@wolaixunshan ~]# cat /tmp/python.txt 
    张鋆康
    ABCDEFG
    HIJKLMN
    OPQRST
    UVWXYZ
    [root@wolaixunshan ~]# cat py1.py
    #!/usr/bin/python3
    #-*- coding:UTF-8 -*-
    f = open("/tmp/python.txt","r")
    print("文件名为:",f.name)
    line = f.readline(2).strip()
    print("读取一行的前两个字符:",line)
    f.seek(0)
    line1 = f.readline().strip()
    print("读取一整行:",line1)
    f.close()
    [root@wolaixunshan ~]# python3 py1.py 
    文件名为: /tmp/python.txt
    读取一行的前两个字符: 张鋆
    读取一整行: 张鋆康

      9.tell(self)

      说明:返回文件的当前位置,即文件指针当前位置

      语法:file.tell()

      返回值:返回文件的当前位置;

      实例:

    张鋆康
    ABCDEFG
    HIJKLMN
    OPQRST
    UVWXYZ
    [root@wolaixunshan ~]# vim py1.py 
    #!/usr/bin/python3
    #-*- coding:UTF-8 -*-
    f = open("/tmp/python.txt","r")
    print("文件名为:",f.name)
    line = f.readline().strip()
    print("读取一行:",line)
    num = f.tell()
    print("当前光标所在位置:",num)                                                              
    f.close()
    [root@wolaixunshan ~]# python3 py1.py 
    文件名为: /tmp/python.txt
    读取一行: 张鋆康
    当前光标所在位置: 10

      10.truncate(self, size: int = None)

      说明:用于从文件的首行首字符开始截断,截断文件为 size 个字符,无 size 表示从当前位置截断;截断之后 V 后面的所有字符被删除,其中 Widnows 系统下的换行代表2个字符大小。

      语法:file.truncate(self, size: int = None)

      参数:size ---------- > 如果存在则文件截断为size字节,没有参数的话则截断到光标出;

      实例:

    [root@wolaixunshan ~]# cat /tmp/python.txt 
    张鋆康
    ABCDEFG
    HIJKLMN
    OPQRST
    UVWXYZ
    [root@wolaixunshan ~]# vim py1.py 
    #!/usr/bin/python3
    #-*- coding:UTF-8 -*-
    f = open("/tmp/python.txt","r+")
    print("文件名为:",f.name)
    f.seek(6)
    f.truncate()                                                                                 
    f.close()
    [root@wolaixunshan ~]# cat /tmp/python.txt 
    张鋆[root@wolaixunshan ~]#
    
    -----------------有参数截取-----------------------------------------
    [root@wolaixunshan ~]# cat /tmp/python.txt 
    张鋆康
    ABCDEFG
    HIJKLMN
    OPQRST
    UVWXYZ
    [root@wolaixunshan ~]# vim py1.py 
    #!/usr/bin/python3
    #-*- coding:UTF-8 -*-
    f = open("/tmp/python.txt","r+")
    print("文件名为:",f.name)
    f.seek(6)
    f.truncate(15)                                                                               
    f.close()
    [root@wolaixunshan ~]# python3 py1.py 
    文件名为: /tmp/python.txt
    [root@wolaixunshan ~]# cat /tmp/python.txt 
    张鋆康
    ABCDE[root@wolaixunshan ~]# 

      11.file.write(str)

      说明:用于向文件中写入指定字符串。在文件关闭前或缓冲区刷新前,字符串内容存储在缓冲区中,这时你在文件中是看不到写入的内容的。

    如果文件打开模式带 b,那写入文件内容时,str (参数)要用 encode 方法转为 bytes 形式,否则报错:TypeError: a bytes-like object is required, not 'str'。

      语法:file.write(str)

      参数:str ---------> 要写入文件的字符串;

      返回值:返回的是写入的字符长度;

      实例:

    [root@wolaixunshan ~]# cat /tmp/python.txt 
    张鋆康
    ABCDE[root@wolaixunshan ~]# cat py1.py
    #!/usr/bin/python3
    #-*- coding:UTF-8 -*-
    f = open("/tmp/python.txt","r+")
    print("文件名为:",f.name)
    f.write("你好呀!")
    f.close()
    
    [root@wolaixunshan ~]# python3 py1.py 
    文件名为: /tmp/python.txt
    [root@wolaixunshan ~]# cat /tmp/python.txt 
    你好呀!CDE[root@wolaixunshan ~]#

      12.file.writelines()

      说明:用于向文件中写入一序列的字符串。这一序列字符串可以是由迭代对象产生的,如一个字符串列表。换行需要制定换行符 。

      语法:file.writelines(item)

      参数:item ------> 要写入文件的字符串序列。

      实例:

    [root@wolaixunshan ~]# cat /tmp/python.txt 
    张鋆康
    
    [root@wolaixunshan ~]# cat py1.py 
    #!/usr/bin/python3
    #-*- coding:UTF-8 -*-
    f = open("/tmp/python.txt","r+")
    print("文件名为:",f.name)
    li = ["中国","北京","沙河"]
    f.writelines(li)
    f.close()
    
    [root@wolaixunshan ~]# python3 py1.py 
    文件名为: /tmp/python.txt
    [root@wolaixunshan ~]# cat /tmp/python.txt 
    中国北京沙河[root@wolaixunshan ~]# 

    五、文件内的光标移动

      1.read(3)

      文件打开方式为文本模式时,代表读取3个字符;

      文件打开方式为b模式时,代表读取3个字节;

      2.其余的文件内光标移动都是以字节为单位如seek,tell,truncate

      

      注意:seek有三种移动方式0,1,2,其中1和2必须在b模式下进行,但无论哪种模式,都是以bytes为单位移动的;

       truncate是截断文件,所以文件的打开方式必须可写,但是不能用w或w+等方式打开,因为那样直接清空文件了,所以truncate要在r+或a或a+等模式下测试效果;

    六、文件的修改

      文件的数据是存放于硬盘上的,因而只存在覆盖、不存在修改这么一说,我们平时看到的修改文件,都是模拟出来的效果,具体的说有两种实现方式:

      方式一:将硬盘存放的该文件的内容全部加载到内存,在内存中是可以修改的,修改完毕后,再由内存覆盖到硬盘(word,vim,nodpad++等编辑器)

    import os
    
    with open('a.txt') as read_f,open('.a.txt.swap','w') as write_f:
        data=read_f.read() #全部读入内存,如果文件很大,会很卡
        data=data.replace('alex','SB') #在内存中完成修改
    
        write_f.write(data) #一次性写入新文件
    
    os.remove('a.txt')
    os.rename('.a.txt.swap','a.txt')

      方式二:将硬盘存放的该文件的内容一行一行地读入内存,修改完毕就写入新文件,最后用新文件覆盖源文件;

    import os
    
    with open('a.txt') as read_f,open('.a.txt.swap','w') as write_f:
        for line in read_f:
            line=line.replace('alex','SB')
            write_f.write(line)
    
    os.remove('a.txt')
    os.rename('.a.txt.swap','a.txt')

       监听文件的输入例子:

    f = open("123.txt",encoding="utf-8")
    while 1:
        line = f.readline()
        if line:
            print(line)

    七、正则表达式

    1.介绍:

      正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符以及这些特定字符的组合,组成一个“规则字符串”,这个规则字符串用来表达对字符串的一种过滤逻辑;

    2.特点:

      a.逻辑性、灵活性和功能性非常强;

      b.可以迅速用极简的方式达到字符串的复杂控制;

      c.对于刚接触的人来说,比较晦涩难懂;

    3.场景:

      a.从大段的文字中找到符合规则的内容;

      b.爬虫,从网页的字符串中获取你想要的数据;

      c.日志分析,提取所需要的数据;

      d.判断某个字符串是否完全符合规则:比如表单验证:手机号、QQ号、邮箱、银行卡、身份证。。。

    4.正则表达式的规则:

      制定好正则表达式的规则,然后从指定的字符串中找到符合规则的子串;

    5.python中的正则表达式大致分类:

      a.元字符  b.模式  c.函数  d.re内置对象用法  e.分组用法  f.环视用法

      所有关于正则表达式的操作都使用python标准库的re模块;

      1)字符组:

      用 [ ] 写在中括号中的内容,都出现在下面的某一个字符的位置上都是负责规则的;

      例如: [0-9]      #匹配数字

          [a-z]      #匹配小写字母

          [A-Z]      #匹配大写字母

          [a-zA-Z]      #匹配大小写字母

          [a-zA-Z0-9]   #匹配大小写字母+数字

          [a-zA-Z0-9_]   #匹配数字字母下划线

      注意:有一些有特殊意义的元字符进入字符组中会回复它本来的意义 :  .  |  [ ]  ( )

      

      2)转义符:

      用“”来表示;

      3)元字符:

      例如: w        #匹配数字字母下划线,相当于[a-zA-Z0-9_]

          d        #匹配所有的数字,相当于[0-9]

          s        #匹配所有的空白符,包括换行符、制表符、空格

                   #匹配所有的换行符

                    #匹配所有的制表符

          [space]      #匹配所有的空格,注意[space]用空格来表示

          W         #匹配非数字字母下划线,也就是w取反;

          D        #匹配非数字,也就是d取反;

          S        #匹配非空白符,也就是s取反

          ^         #匹配字符串的开始

          $         #匹配字符串的结尾

          .          #匹配除换行符以外的任意字符

          []         #只要出现在中括号内的内容都可以被匹配

          [^]          #只要不出现在中括号中的内容都可以被匹配;

          a|b        #或,符合a规则的或者b规则的都可以被匹配;

                如果a规则是b规则的一部分,且a规则比b规则要苛刻/长,就把a规则写在前面;将更复杂的更长的规则写在最前面

          ()        #分组,表示给几个字符加上量词约束的需求的时候,就给这些量词分在一个组;

      

      4)量词:

      例如: {n}       #表示 这个量词之前的字符出现n次

          {n,}        #表示这个量词之前的字符至少出现n次

          {n,m}       #表示这个量词之前的字符出现n-m次

          ?       #表示匹配量词之前的字符出现 0次 或者 1次 表示可有可无;

          +        #表示匹配量词之前的字符出现 1次 或者 多次

          *         #表示匹配量词之前的字符出现 0次 或者 多次

     6.例子:

    贪婪匹配的过程:先整个匹配完合规的,然后在回溯到最后一个字符地方;

     6.python中的正则

      python中的正则需要我们加载正则模块re之后才能使用;import re;re 模块使 Python 语言拥有全部的正则表达式功能

      re在python中的使用方式:

    查找:

      1.findall

      说明:在字符串中找到正则表达式所匹配所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。

      语法:re.findall(pattern,str,flag)

      参数:pattern ------------> 正则表达式

         str  -----------------> 要匹配的字符串

         flag -----------------> 标志,之后会讲

      返回值:如果匹配到子串,则返回一个列表,列表元素为所匹配的子串,如果没有找到匹配的,则返回空列表;

      实例:

    >>> import re           #导入re正则模块
    >>> st = "sjkhk172按实际花费928"      #定义字符串
    >>> ret = re.findall("d+",st)              #使用re模块中的findall查找所有符合规则的数字
    >>> print(ret)    
    ['172', '928']
    >>> ret = re.findall("d",st)
    >>> print(ret)
    ['1', '7', '2', '9', '2', '8']
    >>> ret = re.findall("-",st)    #没有匹配到的则返回一个空列表
    >>> print(ret)
    []
    re.findall(正则表达式,字符串,flag)

      需要注意的是:findall有一个优先级的概念,这个优先级只有在正则表达式里使用了括号时才生效。

      使用finall函数时如果在正则中加入了括号,则finall函数优先返回括号里的内容,例如:

    #例如:
    import re
    ##1、匹配一篇英文文章的标题 类似 The Voice Of China
    ret = re.findall("([A-Z][a-z]* ?)+","The Voice Of China")
    print(ret)
    
    ----------- 输出结果 --------------------------------------------
    ['China']
    
    #这是因为我们在使用fildall方法时在正则里加入了括号,这时会优先返回括号里的内容,又因为China是最后一个匹配上的,所有就只返回了China
    fildall 优先级

      那么,我们就上题的要求,怎么去除这种优先级呢?只需在括号里的开头写上?:就表示取消优先级权限,恢复默认,例如:

    import re
    ##1、匹配一篇英文文章的标题 类似 The Voice Of China
    ret = re.findall("(?:[A-Z][a-z]* ?)+","The Voice Of China")
    print(ret)
    
    #只需要在括号里的开头加上?:就可以取消了
    fildall 取消优先级

     

      2.search

      说明:从左到右扫描整个字符串,并返回第一个成功匹配的子串的匹配对象,可以通过这个匹配对象的group方法来查看这个匹配成功的子串;

      语法:re.search(pattern, string, flags=0)

         参数:pattern ------------> 正则表达式

          str  -----------------> 要匹配的字符串

          flag -----------------> 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等

      返回值:如果成功匹配则返回一个匹配的对象,注意是个对象,对象里有第一个成功匹配的子串;如果没有匹配上,则返回None;

      group是匹配对象的一个方法;

      用法:匹配对象.group(num=0)

      使用说明:a.group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组;

           b.group()默认组号是0,返回这个匹配成功的子串;

           c.当nun=1时,则返回这个成功匹配的子串的第一组;

      实例:

    >>> import re
    >>> st = "sjkhk172按实际花费928"
    >>> ret = re.search("d+",st)    #生成一个匹配对象
    >>> print(ret)
    <re.Match object; span=(5, 8), match='172'> 匹配对象里的内容包含了匹配成功的子串,以及子串在字符串中的索引位置(5,8)
    >>> print(ret.group())
    172
    >>> ret = re.search("-",st)      #当匹配不到时,则返回None
    >>> print(ret)
    None
    >>> print(ret.group())     #这时候再使用group方法时会报错
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    AttributeError: 'NoneType' object has no attribute 'group'
    re.search
    >>> st = "2018-06-12 08:26:54"
    >>> ret = re.search("([1-9]d{3})-(1[0-2]|0?[1-9])-([12][0-9]|0?[0-9])",st)
    >>> print(ret.group())
    2018-06-12
    >>> print(ret.group(1))
    2018
    >>> print(ret.group(2))
    06
    >>> print(ret.group(3))
    12
    re.search组方法的使用

      3.match

      说明:从字符串的起始位置开始匹配,并返回第一个成功匹配的子串的匹配对象,如果匹配不成功,则返回None;相当于search正则表达式前加了一个尖角号^

      语法:re.match(pattern, string, flags=0)

      参数:pattern ------------> 正则表达式

          str  -----------------> 要匹配的字符串

          flag -----------------> 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等

      返回值:匹配成功re.match方法返回一个匹配的对象,否则返回None;

      group是匹配对象的一个方法;

      用法:匹配对象.group(num=0)

      使用说明:a.group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组;

           b.group()默认组号是0,返回这个匹配成功的子串;

           c.当nun=1时,则返回这个成功匹配的子串的第一组;

      实例:

    #定义两个字符串
    >>> st1 = "172china16beijing13"       
    >>> st2 = "china172shanghai16haha"
    >>> 
    >>> ret1 = re.match("d+",st1)
    >>> print(ret1.group(0))
    172
    >>> ret2 = re.match("d+",st2)
    >>> print(ret2.group(0))
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    AttributeError: 'NoneType' object has no attribute 'group'
    #通过上面例子可知,match是匹配字符串的起始位置的且只匹配第一个成功的子串,如果没有匹配到则返回None,这时再用group方法查看的话会报错;
    re.match

    替换、切割:

      1.split

      说明:split 方法按照能够匹配的子串将字符串分割后返回列表;默认是不保留匹配的子串的;切割是一分为二的,所以如果切割符是在开头或结尾则会产生空子串。

      语法:re.split(pattern, string[, maxsplit=0, flags=0])

      参数:pattern --------> 正则表达式

         string ----------> 要匹配的字符串

         maxsplit -------> 切割的次数,默认全部切割,

         flag  -------------> 标志位。以后讲

      返回值:返回一个切割后的列表,列表中的元素就是被切割后的各子串,但不包括切割符,也就是匹配的子串;

      实例:

    #1.使用正则匹配出子串,用匹配后的子串作为分隔符来分隔,
    >>> st1 = "172china16beijing13"
    >>> ret1 = re.split("d+",st1)
    >>> print(ret1)
    ['', 'china', 'beijing', '']
    #首先因为默认分隔符也就是子串是不能保留在列表中的,所以列表中是没有匹配的子串的,又因为此题中匹配的子串首尾都有,所以会在首尾产生两个空字符串;
    
    
    #2.使用正则匹配出的子串作分隔符,对字符串进行分隔,且只分隔1次;
    >>> st2 = "china172shanghai16haha"
    >>> ret2 = re.split("d+",st2,1)
    >>> print(ret2)
    ['china', 'shanghai16haha']
    re.split

      那么,我们如果想在列表中保留我们匹配的字符串,也就是说如果我们想要保留分隔符,那么应该怎么办呢?

      我们只需要给要匹配的的内容外加上括号就行,在split里就表示保留匹配的子串,例如:

    #在正则表达式规则中给匹配内容加上括号,就表示在列表中保存这些匹配的子串;
    >>> st1 = "172china16beijing13"
    >>> ret1 = re.split("(d+)",st1)
    >>> print(ret1)
    ['', '172', 'china', '16', 'beijing', '13', '']
    #可以看到匹配成功的子串都保留下来了
    re.split 在列表中保留匹配的子串

      2.sub

      说明:用于替换字符串中的匹配项

      语法:re.sub(pattern, repl, string, count=0)

      参数:pattern ---------> 正则表达式;

         repl  -------------> 新的字符串,也可为一个函数

         string ------------>  要被查找替换的原始字符串

         count -------------> 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配

      返回值:返回一个替换后新的字符串;如果匹配不成功,则返回原字符串;

      实例:

    #1.匹配成功后,替换所有匹配的子串
    >>> st1 = "172china16beijing13"
    >>> ret1 = re.sub("d+","ZJK",st1)
    >>> print(ret1)
    ZJKchinaZJKbeijingZJK
    
    #2.匹配不成功,返回原字符串
    >>> ret1 = re.sub("-","ZJK",st1)
    >>> print(ret1)
    172china16beijing13
    
    #3.匹配成功后,替换1处匹配的子串
    >>> ret1 = re.sub("d+","ZJK",st1,1)
    >>> print(ret1)
    ZJKchina16beijing13
    re.sub 替换

      3.subn

      说明:用于替换字符串中的匹配项,并告知替换了多少处。

      语法:re.sub(pattern, repl, string, count=0)

      参数:pattern ---------> 正则表达式;

         repl  -------------> 新的字符串,也可为一个函数

         string ------------>  要被查找替换的原始字符串

         count -------------> 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配

      返回值:返回一个元组,匹配成功则元组的第一个元素为替换后的新字符串,否则第一个元素为原字符串,元组的第二个元素为替换的次数,若没有替换,则为0;

      实例:

    #定义一个字符串;
    >>> st1 = "172china16beijing13"
    
    #匹配成功后
    >>> ret1 = re.subn("d+","ZJK",st1)
    >>> print(ret1)
    ('ZJKchinaZJKbeijingZJK', 3)
    #匹配不成功
    >>> ret1 = re.subn("-","ZJK",st1)
    >>> print(ret1)
    ('172china16beijing13', 0)
    #设置替换的次数
    >>> ret1 = re.subn("d+","ZJK",st1,2)
    >>> print(ret1)
    ('ZJKchinaZJKbeijing13', 2)
    re.subn 替换以及替换的次数

     re模块的进阶

      优秀的程序,看代码的这几个方面,时间、空间、扩展

      1.使用正则表达式节省解决问题的时间

      complie

      说明:compile 函数用于编译正则表达式,生成一个正则表达式( Pattern )对象,供 正则其他函数的使用;

      优点:一次编译,多次使用,节省了执行时间,在使用正则表达式执行其他操作时不用在去对正则进行解释了,而是直接使用第一次编译好的正则;

      语法:re.compile(pattern[, flags])

      参数:pattern ----------->   一个字符串形式的正则表达式

         flags 可选,表示匹配模式,比如忽略大小写,多行模式等,具体含义下面会说;

      实例:

    #导入模块
    >>> import re
    #定义正则表达式,系统会对其进行编译
    >>> pat = re.compile("d+")
    >>> print(pat)
    re.compile('\d+')
    >>> st = "172china16beijing13"
    直接调用定义的正则表达式pat
    >>> ret = pat.findall(st)
    >>> print(ret)
    ['172', '16', '13']
    >>> ret = pat.search(st)
    >>> print(ret)
    <re.Match object; span=(0, 3), match='172'>
    >>> print(ret.group())
    172
    >>> ret = pat.sub("HOOK",st)
    >>> print(ret)
    HOOKchinaHOOKbeijingHOOK
    re.conplie 定义正则表达式,提高代码执行时间

      

      2.使用正则表达式也可以节省空间,也就是节省内存;

      finditer

      说明:和 findall 类似,在字符串中找到正则表达式所匹配的所有子串,并把它们作为一个迭代器返回;这样的话我们在取值时就是在迭代器里取回,迭代器的优点就不说了;

      注意:需要通过循环+group的形式取值;

      语法:re.finditer(pattern, string, flags=0)

      参数:pattern ------------> 正则表达式

         str  -----------------> 要匹配的字符串

         flag -----------------> 标志,之后会讲

      返回值:返回一个迭代器

      实例:

    >>> st = "172china16beijing13"
    >>> ret = re.finditer("d+",st)     #得到一个迭代器
    >>> print(ret)
    <callable_iterator object at 0x7fa22f1314a8>
    >>> print(list(ret))   #将迭代器转换为列表
    [<re.Match object; span=(0, 3), match='172'>, <re.Match object; span=(8, 10), match='16'>, <re.Match object; span=(17, 19), match='13'>]
    #如果想打印的可以不进行列表转换,直接for循环ret,然后给每个元素加上group方法;
    re.finditer 将匹配结果放到迭代器中,

    正则表达式修饰符—可选标志:

      

          

  • 相关阅读:
    yablog: calculate cosine with python numpy
    HDF
    numarray 1.5.1
    Angles between two ndimensional vectors in Python Stack Overflow
    3D stem plot
    linq to sql一定要注意的地方!
    将IRepository接口进行抽象,使它成为数据基类的一个对象,这样每个子类都可以有自己的最基础的CURD了
    (SQL)比较一个集合是否在另一个集合里存在的方法
    linq to sql统一更新方法,直接返回更新的对象(解决更新后再刷新数据错误显示问题)
    LINQ TO SQL数据实体应该这样设计(解决多表关联问题)
  • 原文地址:https://www.cnblogs.com/zhangjunkang/p/9431283.html
Copyright © 2020-2023  润新知