4.9 python 正则表达式/re模块/shutil模块/logging模块 学习笔记

文章目录

  • 1 正则表达式
    • 1)用途
    • 2)元字符
    • 3)量词
    • 4)贪婪匹配
    • 5)惰性匹配
    • 6)转义符
  • 2 re模块
    • 1)相关方法
    • 2)分组命名
  • 3 shutil 模块
    • 1)拷贝
    • 2)删除
    • 3)移动
    • 4)查看当前磁盘使用空间
    • 5)压缩文件夹
    • 6)解压文件夹
  • 4 logging模块
    • 1)输入内容等级
    • 2)logging 模块作用
    • 3)使用

1 正则表达式

1)用途

  • 检测一个输入的字符串是否合法 —— web开发项目 表单验证
    • 用户输入一个内容的时候,我们要提前做检测
    • 能够提高程序的效率并且减轻服务器的压力
  • 从一个大文件中找到所有符合规则的内容 —— 日志分析、爬虫
    • 能够高效地从医大段文字中快速找到符合规则的内容

2)元字符

在正则表达式中帮助我们表示匹配的内容的符号都是正则中的原字符

  • 字符组:[] 一个中括号只表示一个字符位置 # [abc] [0-9] [a-zA-Z]

  • 非字符组:[^]

  • \d 匹配一位任意数字

  • \w 匹配数字、字母、下划线

  • \s 匹配所有空白(包括空格( )、tab(\t)、enter(\n))

  • \W 匹配非数字、字母、下划线

  • \D 非数字

  • \S 非空白

  • \b 匹配单词结尾字符 #

  • [\d\D] [\w\W] [\s\S] 表示匹配所有

  • . 表示匹配除换行符之外的所有

  • [^\d] # 匹配所有非数字

  • ^ 开始匹配符

  • $ 终止匹配符

  • | 或(优先匹配符号左边,只能匹配一边)

  • \ 转义符

  • () 约束|描述范围作用域

3)量词

  • {n} 表示匹配n次
  • {n, } 表示最少匹配n次
  • {n, m} 表示最少匹配n次、最多m次
  • ? 表示匹配0次或1次
  • + 表示匹配1次或多次
    • 整数 \d+
    • 小数 \d+\.\d+
    • 整数或小数 \d+(\.\d*)?
  • * 表示匹配0次或多次

4)贪婪匹配

  • 在量词允许的情况下,尽量多的匹配

  • .*x 表示匹配任意字符,任意多次数,遇到最后一个x才停下来

  • eg: \d{3, }6 此处结尾会是最后一个匹配到的6

5)惰性匹配

  • 在量词允许的情况下,尽量少的匹配
  • .*?x 表示匹配任意字符,任意多次数,一旦遇到x就停下来
  • eg: \d{3, }?6 此处结尾会是第一个匹配到的6

6)转义符

\ 取消字符特殊意义 [.] 匹配.符号

2 re模块

在python中操作正则表达式

1)相关方法

  • re.findall(‘正则表达式’, 需要匹配的字符串)

    • 返回所有匹配到的值组成的数组
    • 取所有符合条件的,但是优先显示分组中的
  • re.search(‘正则表达式’, 需要匹配的字符串)

    • 只取第一个符合条件的
    • 返回一个对象
    • 没找到也会返回一个空对象
    • 对这个对象使用 对象.group() 方法可以获取匹配到的值,空对象会报错
      • 对象.group() 的结果和 对象.group(0) 的结果一致
      • 对象.group(n) 指定获取第n个分组中匹配到的内容
  • re.findall() 分组优先使用原因和好处

import re
ret = re.findall('<\w+>(\w+)', '

bafhgakjkf54sf5dsg452as4fds

'
) print(ret) # ['bafhgakjkf54sf5dsg452as4fds'] ret2 = re.search('<\w+>(\w+)', '

bafhgakjkf54sf5dsg452as4fds

'
) print(ret2) # print(ret2.group()) #

bafhgakjkf54sf5dsg452as4fds

print(ret2.group(0)) #

bafhgakjkf54sf5dsg452as4fds

print(ret2.group(1)) # bafhgakjkf54sf5dsg452as4fds
  • re.split(正则表达式, 被切割字符)

    • 根据正则表达式切割某个字符串

      ret = re.split('\d+','alex222wusir')
      ret = re.split('\d(\d)\d','alex123wusir')
      print(ret)
      
  • re.sub(正则表达式, 替换字符, 被替换字符串)

    • 根据正则表达式替换字符串的匹配字符

    • 返回替换后字符串

      ret = re.sub('\d+','H','alex123wusir456',1)
      print(ret)
      
  • re.subn(正则表达式, 替换字符, 被替换字符串)

    • 根据正则表达式替换字符串的匹配字符

    • 返回元组(替换后字符串, 替换次数)

      ret = re.subn('\d+','H','alex123wusir456')
      print(ret)
      
  • re.match(正则表达式, 字符串)

    • 相当于search,但是规定必须开头是什么

    • match和search

      • match规定这个字符串必须是什么样

      • search用于字符串是不是含有满足条件的子字符串

        ret = re.match('\d+','123eva456taibai')
        print(ret.group())
        
        ret = re.search('^\d+','123eva456taibai')
        print(ret.group())
        
  • re.compile(正则表达式)

    • 同一个正则表达式要被使用多次

    • 节省了多次解析同一个正则表达式的时间

      ret = re.compile('\d+')
      res1 = ret.search('alex37176')
      res2 = ret.findall('alex37176')
      print(res1)
      print(res2)
      
  • re.finditer()

    • 相当于findall(),但是返回一个迭代器

    • 节省空间

      ret = re.finditer('\d+','agks1ak018093')
      for i in ret:
          print(i.group())
      
  • 先compile,再finditer

    • 既节省时间又节省空间

      ret= re.compile('\d+')
      res = ret.finditer('agks1ak018as093')
      for r in res:
          print(r.group())
      
  • 补充知识

    • list尽量不用insert()和pop(n) 节省空间

    • 程序要求

      1. 功能

      2. 性能

        • 时间:

          • 完成一个代码所需要执行的代码行数
          • 在执行代码的过程中,底层程序是如何工作的
        • 空间:

          • 占用了宝贵的内存条资源
          • 影响程序的执行效率
      3. 用户体验

2)分组命名

  • 分组命名规则:

    • 设置分组命名:(?P<名字>正则表达式)
    • 取命名分组:ret.group(‘名字’)
    ret = re.search('\d(\d)\d(\w+?)(\d)(\w)\d(\d)\d(?P\w+?)(\d)(\w)\d(\d)\d(?P\w+?)(\d)(\w)',
              '123abc45678agsf_123abc45678agsf123abc45678agsf')
    
    print(ret.group('name1'))
    print(ret.group('name2'))
    
  • 分组命名引用

    import re
    exp= 'akd7008&(&*)hgdwuih008&(&*)hgdwuih'
    ret= re.search('<(?P\w+)>.*?',exp)
    print(ret)
    
    # exp= 'akd7008&(&*)hgdwuih008&(&*)hgdwuih'
    # ret= re.search(r'<(\w+)>.*?',exp)
    # ret= re.search('<(\w+)>.*?',exp)
    # print(ret)
    
    # ret=re.findall(r"\d+\.\d+|(\d+)","1-2*(60+(-40.35/5)-(-4*3))")
    # print(ret)
    # ret = ['1', '2', '60', '', '5', '4', '3','','']
    # ret.remove('')
    # print(ret)
    # ret = filter(lambda n:n,ret)
    # print(list(ret))
    

3 shutil 模块

高级的文件、文件夹、压缩包处理模块

1)拷贝

  • shutil.copyfileobj(fsrc, fdst[, length]) 将文件内容拷贝到另一个文件中

    import shutil
    shutil.copyfileobj(open('old.xml','r'), open('new.xml', 'w'))
    
  • shutil.copyfile(src, dst) 拷贝文件

    shutil.copyfile('f1.log', 'f2.log') #目标文件无需存在
    
  • shutil.copymode(src, dst) 仅拷贝权限。内容、组、用户均不变

    shutil.copymode('f1.log', 'f2.log') #目标文件必须存在
    
  • shutil.copystat(src, dst) 仅拷贝状态的信息,包括:mode bits, atime, mtime, flags

    shutil.copystat('f1.log', 'f2.log') #目标文件必须存在
    
  • shutil.copy(src, dst) 拷贝文件和权限

    import shutil
    shutil.copy('f1.log', 'f2.log')
    
  • shutil.copy2(src, dst) 拷贝文件和状态信息

    import shutil
    shutil.copy2('f1.log', 'f2.log')
    
  • shutil.ignore_patterns(\*patterns)
    shutil.copytree(src, dst, symlinks=False, ignore=None) 递归的去拷贝文件夹

    import shutil
    shutil.copytree('folder1', 'folder2', ignore=shutil.ignore_patterns('*.pyc', 'tmp*')) #目标目录不能存在,注意对folder2目录父级目录要有可写权限,ignore的意思是排除 
    
    import shutil
    
    shutil.copytree('f1', 'f2', symlinks=True, ignore=shutil.ignore_patterns('*.pyc', 'tmp*'))
    
    '''
    通常的拷贝都把软连接拷贝成硬链接,即对待软连接来说,创建新的文件
    '''
    

2)删除

  • shutil.rmtree(path[, ignore_errors[, onerror]]) 递归的去删除文件

    import shutil
    shutil.rmtree('folder1')
    

3)移动

  • shutil.move(src, dst) 递归的去移动文件,它类似mv命令,其实就是重命名

    import shutil
    shutil.move('folder1', 'folder3')
    

4)查看当前磁盘使用空间

total, used, free = shutil.disk_usage("c:\\")
print("当前磁盘共: %iGB, 已使用: %iGB, 剩余: %iGB"%(total / 1073741824, used / 1073741824, free / 1073741824))

5)压缩文件夹

  • shutil.make_archive(base_name, format,...) 创建压缩包并返回文件路径,例如:zip、tar
    • base_name: 压缩包的文件名,也可以是压缩包的路径。只是文件名时,则保存至当前目录,否则保存至指定路径
      • 如 data_bak =>保存至当前路径
      • 如:/tmp/data_bak =>保存至/tmp/
    • format: 压缩包种类,“zip”, “tar”, “bztar”,“gztar”
    • root_dir: 要压缩的文件夹路径(默认当前目录)
    • owner: 用户,默认当前用户
    • group: 组,默认当前组
    • logger: 用于记录日志,通常是logging.Logger对象
#将 /data 下的文件打包放置当前程序目录
import shutil
ret = shutil.make_archive("data_bak", 'gztar', root_dir='/data')
  
  
#将 /data下的文件打包放置 /tmp/目录
import shutil
ret = shutil.make_archive("/tmp/data_bak", 'gztar', root_dir='/data')

6)解压文件夹

shutil 对压缩包的处理是调用 ZipFile 和 TarFile 两个模块来进行的

import zipfile

# 压缩
z = zipfile.ZipFile('laxi.zip', 'w')
z.write('a.log')
z.write('data.data')
z.close()

# 解压
z = zipfile.ZipFile('laxi.zip', 'r')
z.extractall(path='.')
z.close()
# 压缩
t=tarfile.open('/tmp/egon.tar','w')
t.add('/test1/a.py',arcname='a.bak')
t.add('/test1/b.py',arcname='b.bak')
t.close()


# 解压
t=tarfile.open('/tmp/egon.tar','r')
t.extractall('/egon')
t.close()

4 logging模块

1)输入内容等级

import logging
# 输出内容是有等级的 : 默认处理warning级别以上的所有信息
logging.debug('debug message')          # 调试
logging.info('info message')            # 信息
logging.warning('warning message')      # 警告
logging.error('error message')          # 错误
logging.critical('critical message')    # 批判性的

2)logging 模块作用

  • 排错处理

    # 排错处理实例
    def cal_mul(exp):
        exp = 4*6
        logging.debug('4*6 = 24')
        return 24
    def cal_div():
        pass
    def cal_add():
        pass
    def cal_sub(exp):
        exp = 3-24
        logging.debug('cal_sub :3-24 = 21')
        return 21
    
    def cal_inner_bracket(exp2):
        exp2 = 3-4*6
        ret = cal_mul(4*6)
        exp2 = 3-24
        ret = cal_sub(3-24)
        logging.debug('3-4*6 = -21')
        return -21
    
    def main(exp):
        exp =(1+2*(3-4*6))/5
        ret = cal_inner_bracket(3-4*6)
        return ret
    
    logging.basicConfig(level=logging.DEBUG)
    ret = main('(1+2*(3-4))/5')
    print(ret)
    
  • 数据分析 —— 记录到日志

# 记录日志

# 输出到屏幕
logging.basicConfig(
    format='%(asctime)s - %(name)s - %(levelname)s[line :%(lineno)d]-%(module)s:  %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S %p',
)
logging.warning('warning message test2')
logging.error('error message test2')
logging.critical('critical message test2')
# 
# 输出到文件,并且设置信息的等级
logging.basicConfig(
    format='%(asctime)s - %(name)s - %(levelname)s[line :%(lineno)d]-%(module)s:  %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S %p',
    filename='tmp.log',
    level= logging.DEBUG
)
# logging.debug('debug 信息错误 test2')
# logging.info('warning 信息错误 test2')
# logging.warning('warning message test2')
# logging.error('error message test2')
# logging.critical('critical message test2')

3)使用

# 同时向文件和屏幕上输出 和 解决文件乱码
import logging
fh = logging.FileHandler('tmp.log', encoding='utf-8')
# fh2 = logging.FileHandler('tmp2.log',encoding='utf-8')
sh = logging.StreamHandler()
logging.basicConfig(
    format = '%(asctime)s - %(name)s - %(levelname)s[line :%(lineno)d]-%(module)s:  %(message)s',
    datefmt = '%Y-%m-%d %H:%M:%S %p',
    level = logging.DEBUG,
    # handlers = [fh,sh,fh2]
    handlers = [sh, fh],
)
logging.debug('debug 信息错误 test2')
logging.info('warning 信息错误 test2')
logging.warning('warning message test2')
logging.error('error message test2')
logging.critical('critical message test2')
# 做日志的切分
import logging
import time
from logging import handlers
sh = logging.StreamHandler()
rh = handlers.RotatingFileHandler('myapp.log', maxBytes=1024,backupCount=5)   # 按照大小做切割
fh = handlers.TimedRotatingFileHandler(filename='x2.log', when='s', interval=5, encoding='utf-8')
logging.basicConfig(
    format='%(asctime)s - %(name)s - %(levelname)s[line :%(lineno)d]-%(module)s:  %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S %p',
    level= logging.DEBUG,
    # handlers=[fh,sh,fh2]
    handlers=[fh,rh,sh]
)
for i in range(1,100000):
    time.sleep(1)
    logging.error('KeyboardInterrupt error %s'%str(i))

参考原文链接1
参考原文链接2

你可能感兴趣的:(python,python,正则表达式,logging)