正则表达式

字符组[字符],同一个位置上能放的所有字符集
元字符
\w\d\s
\W\D\S
\n\t
\b
^$ 匹配开始和结束
()分组在对多个字符组整体做量词约束的时候用的,分组是有优先的findall()默认只显示括号里面的,?P命名一个名字为Value的组
| 从左到右匹配,匹配上就不继续匹配了,长的在前面
[^]除了字符组内的其他都匹配
量词 *0~, + 1~, ? 0~1, {n,m}
.匹配除了换行符以外的任意字符
re方法的flags:
re.I(IGNORECASE)忽略大小写,括号内是完整的写法
re.M(MULTILINE)多行模式,改变^和$的行为
re.S(DOTALL)点可以匹配任意字符,包括换行符
re.L(LOCALE)做本地化识别的匹配,表示特殊字符集 \w, \W, \b, \B, \s, \S 依赖于当前环境,不推荐使用
re.U(UNICODE) 使用\w \W \s \S \d \D使用取决于unicode定义的字符属性。在python3中默认使用该flag
re.X(VERBOSE)冗长模式,该模式下pattern字符串可以是多行的,忽略空白字符,并可以添加注释

要导入的包

import sys
import os
import random
import time
from collections import defaultdict
from collections import OrderedDict
from collections import deque
import collections
import queue
from collections import namedtuple
import re

转义的问题

re.findall(r'\\s', r'\s')   # 或者使用\\,或者使用/

知识

# 字符组里面很少出现量词,一般对字符组做量词约束 特殊字符不表达特殊字符的意思的时候统统转义
# 惰性匹配,正常是贪婪匹配,量词后面加?,如.*?x 一直取遇到?后面的内容就停
# findall()返回值为列表,列表中是所有匹配的项
# search()找整个字符串,遇到匹配上的就返回,遇不到返回None,有返回值.group(n)就可以取到,\d(?P<name>\w)+,给分组命名,.group('name')通过名字取值
# match()和search用法差不多,找的规则不一样,match是从头匹配,search是找整个字符串
# split ,sub subn,finditer找到的结果太多,不想占内存,用迭代器
# complie 编译,正则表达式很长且要多次使用的时候进行编译
ret = re.search("<(?P<tag_name>\\w+)>\\w+</(?P=tag_name)>", "<h1>hello</h1>")
# 还可以在分组中利用?<name>的形式给分组起名字
# 获取的匹配结果可以直接用group('名字')拿到对应的值
print(ret.group('tag_name'))  # 结果 :h1
print(ret.group())  # 结果 :<h1>hello</h1>

ret = re.search(r"<(\\w+)>\\w+</\1>", "<h1>hello</h1>")   # \1 取第一组
# 如果不给组起名字,也可以用\序号来找到对应的组,表示要找的内容和前面的组内容一致
# 获取的匹配结果可以直接用group(序号)拿到对应的值
print(ret.group(1))
print(ret.group())  # 结果 :<h1>hello</h1>

匹配整数

ret = re.findall(r"\d+", "1-2*(60+(-40.35/5)-(-4*3))")
print(ret)  # ['1', '2', '60', '40', '35', '5', '4', '3']
ret = re.findall(r"\d+\.\d+|(\d+)", "1-2*(60+(-40.35/5)-(-4*3))")   # 方案一 ,分组优先
ret.remove("")
ret = re.findall(r"-?\d+\.\d*|(-?\d+)", "1-2*(60+(-40.35/5)-(-4*3))")
print(ret)  # ['1', '-2', '60', '', '5', '-4', '3']
ret.remove("")
print(ret)  # ['1', '-2', '60', '5', '-4', '3']

常用匹配数字的正则表达式

'''
1、 匹配一段文本中的每行的邮箱 
2、 匹配一段文本中的每行的时间字符串,比如:‘1990-07-12’;

   分别取出1年的12个月(^(0?[1-9]|1[0-2])$)、一个月的31天:^((0?[1-9])|((1|2)[0-9])|30|31)$

3、 匹配qq号。(腾讯QQ号从10000开始)  [1,9][0,9]{4,}

4、 匹配一个浮点数。 ^(-?\d+)(\.\d+)?$   或者  -?\d+\.?\d*

5、 匹配汉字。      ^[\u4e00-\u9fa5]{0,}$

'''

collections模块

# py文件起名不要用和模块一样的名字,模块本质上是py文件
# 1.namedtuple: 生成可以使用名字来访问元素内容的tuple
Point = namedtuple('point', ['x', 'y', 'z'])
p1 = Point(1, 2, 3)
p2 = Point(3, 2, 1)
print(p1.x)
print(p1.y)
print(p1, p2)
# 花色和數字
Card = namedtuple('card', ['suits', 'number'])
c1 = Card('紅桃', 2)
print(c1)
print(c1.number)
print(c1.suits)
# 2.deque: 双端队列,可以快速的从另外一侧追加和推出对象
# 列表、元组、字典、集合、frozenset、字符串、堆栈:先进后出
# 队列:先进先出FIFO
Q = queue.Queue()
Q.put(10)  # 不能传多个值
Q.put(5)
Q.put(6)
print(Q)  # 得到一个内存地址,不是可迭代的
print(Q.get())
print(Q.get())
print(Q.get())
print(Q.get())   # 取多了之后类似于input,会等待,阻塞在这儿,直到再放一个值就停了
print(Q.qsize())  # 查看队列大小
dq = deque([1, 2])
dq.append('a')   # 从后面放数据 [1,2,'a']
dq.appendleft('b')  # 从前面放数据['b',1,2,'a']
dq.insert(1, 3)  # 向1位置插入一个值 ['b',1,3,2,'a']
print(dq.pop())  # 从后面取数据
print(dq.popleft())  # 从前面取数据
print(dq)  # 可以看见数据,不安全
# 使用list存储数据时,按索引访问元素很快,但是插入和删除元素就很慢了,因为list是线性存储,数据量大的时候,插入和删除效率很低。
# 尽量不要向一个长列表中插入或者删除一个值,会使效率降低。
# deque是为了高效实现插入和删除操作的双向列表,适合用于队列(类似于一个连着一个的结构)和栈:


# 3.Counter: 计数器,主要用来计数
# Counter类的目的是用来跟踪值出现的次数。它是一个无序的容器类型,以字典的键值对形式存储,其中元素作为key,其计数作为value。计数值可以是任意的Interger(包括0和负数)。
# Counter类和其他语言的bags或multisets很相似。
count = collections.Counter('abcdeabcdabcaba')
print(count['a'])

# 输出:Counter({'a': 5, 'b': 4, 'c': 3, 'd': 2, 'e': 1})

# 4.OrderedDict: 有序字典,字典取值非常快,但是占内存,比列表多,有序字典更占内存
d = dict([('a', 1), ('b', 2), ('c', 3)])  # 不常用
# {'a': 1, 'c': 3, 'b': 2}
od = OrderedDict([('a', 1), ('b', 2), ('c', 3)])
# OrderedDict([('a', 1), ('b', 2), ('c', 3)])

# 5.defaultdict: 带有默认值的字典
# {'k1': 大于66 , 'k2': 小于66}
dic = {'k1': [], 'k2': []}
# 原生字典解决方法
values = [11, 22, 33, 44, 55, 66, 77, 88, 99, 90]
my_dict = {}
for value in values:
    if value > 66:
        if 'k1' in my_dict:
            my_dict['k1'].append(value)
        else:
            my_dict['k1'] = [value]
    else:
        if 'k2' in my_dict:
            my_dict['k2'].append(value)
        else:
            my_dict['k2'] = [value]
# defaultdict字典解决方法

values = [11, 22, 33, 44, 55, 66, 77, 88, 99, 90]

my_dict = defaultdict(list)  # 默认有一个list,可以默认其他数据类型,必须时刻调用(callable)的名字,不能是数字

for value in values:
    if value > 66:
        my_dict['k1'].append(value)
    else:
        my_dict['k2'].append(value)
# 使用dict时,如果引用的Key不存在,就会抛出KeyError。如果希望key不存在时,返回一个默认值,就可以用defaultdict:
dd = defaultdict(lambda: 'N/A')  # 可以写匿名函数来解决不可调用的问题
dd['key1'] = 'abc'
print(dd['key1'])  # key1存在
# 'abc'
print(d['key2'])  # key2不存在,返回默认值
# 'N/A'

时间模块

time.sleep(100)   # 程序暂停100ms
print(time.time())  # 返回以秒为单位的浮点数,从1970年1月1日午夜(Unix计算机的时间开始日期),时间戳,float类型
# 格式化的时间字符串-字符串类型
# 时间戳时间用于计算机时间
# 结构化时间是个元组:计算时间差计算用的
print(time.strftime("$Y-%m-%d %a %H:%M:%S"))  # 传入格式, %Y年,%m月,%a 星期
print(time.strftime("$Y/%m/%d %H:%M:%S"))

# %y 两位数的年份表示(00-99)
# %Y 四位数的年份表示(000-9999)
# %m 月份(01-12)
# %d 月内中的一天(0-31)
# %H 24小时制小时数(0-23)
# %I 12小时制小时数(01-12)
# %M 分钟数(00=59)
# %S 秒(00-59)
# %a 本地简化星期名称
# %A 本地完整星期名称
# %b 本地简化的月份名称
# %B 本地完整的月份名称
# %c 本地相应的日期表示和时间表示
# %j 年内的一天(001-366)
# %p 本地A.M.或P.M.的等价符
# %U 一年中的星期数(00-53)星期天为星期的开始
# %w 星期(0-6),星期天为星期的开始
# %W 一年中的星期数(00-53)星期一为星期的开始
# %x 本地相应的日期表示
# %X 本地相应的时间表示
# %Z 当前时区的名称
# # %% %号本身
struct_time = time.localtime()  # 元组,结构化时间
print(struct_time)   # 可命名元组
print(struct_time.tm_year)
# 时间戳和结构化时间的转换
t = time.time()
print(time.localtime(t))   # 传入时间戳,得到结构化的时间,北京时间
print(time.gmtime(t))   # 格林威治时间,差八个小时
print(time.mktime(time.localtime()))  # 结构化时间转化为时间戳时间
# 格式化时间转成结构化时间
print(time.strptime('2000-12.31', '%Y-%m.%d'))  # 传入格式化时间的格式
print(time.strftime('%m/%d/%y %H:%M;%S',
                    time.localtime(3000000000000)))   # %y 会把年份前两位省略
print(time.asctime(time.localtime(1500000000000)))  # 格式化时间,可传入结构化时间
print(time.ctime(150000000000))

计算时间差

true_time = time.mktime(time.strptime(
    '2017-09-11 08:30:00', '%Y-%m-%d %H:%M:%S'))
time_now = time.mktime(time.strptime(
    '2017-09-12 11:00:00', '%Y-%m-%d %H:%M:%S'))
dif_time = time_now-true_time
struct_time = time.gmtime(dif_time)
print('过去了%d年%d月%d天%d小时%d分钟%d秒' % (struct_time.tm_year-1970, struct_time.tm_mon-1,
                                   struct_time.tm_mday-1, struct_time.tm_hour,
                                   struct_time.tm_min, struct_time.tm_sec))

random模块

random.random()      # 大于0且小于1之间的小数
random.uniform(1, 3)  # 大于1小于3的小数
random.randint(1, 5)  # 大于等于1且小于等于5之间的整数,包括5
random.randrange(1, 10, 2)  # 大于等于1且小于10之间的奇数,不包括10,2为步长
random.choice([1, '23', [4, 5]])  # # 返回1或者23或者[4,5],接收可迭代的
random.sample([1, '23', [4, 5]], 2)  # 返回列表元素任意2个组合
# 打乱列表顺序
item = [1, 3, 5, 7, 9]
print(random.shuffle(item))  # 打乱次序
print(random.shuffle(item))

生成随机验证码

# str = chr(90)  把数字转换为对应的ASCILL码


def v_code():

    code = ''
    for i in range(5):

        num = random.randint(0, 9)
        alf = chr(random.randint(65, 90))
        add = random.choice([num, alf])
        code = "".join([code, str(add)])

    return code


print(v_code())

os 模块,借助操作系统来发挥作用

os.makedirs('dirname1/dirname2')    # 可生成多层递归目录
os.removedirs('dirname1')    # 若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推
os.mkdir('dirname')    # 生成单级目录;相当于shell中mkdir dirname
os.rmdir('dirname')    # 删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname
os.listdir('dirname')    # 列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印
os.remove()  # 删除一个文件
os.rename("oldname", "newname")  # 重命名文件/目录
os.stat('path/filename')  # 获取文件/目录信息
'''
stat 结构:

st_mode: inode 保护模式
st_ino: inode 节点号。
st_dev: inode 驻留的设备。
st_nlink: inode 的链接数。
st_uid: 所有者的用户ID。
st_gid: 所有者的组ID。
st_size: 普通文件以字节为单位的大小;包含等待某些特殊文件的数据。
st_atime: 上次访问的时间。
st_mtime: 最后一次修改的时间。
st_ctime: 由操作系统报告的"ctime"。在某些系统上(如Unix)是最新的元数据更改的时间,\
    在其它系统上(如Windows)是创建时间(详细信息参见平台的文档)。
'''

os.sep    # 输出操作系统特定的路径分隔符,win下为"\\",Linux下为"/", 跨平台使用
os.linesep    # 输出当前平台使用的行终止符,win下为"\r\n",Linux下为"\n"
os.pathsep    # 输出用于分割文件路径的字符串 win下为;,Linux下为:
os.name    # 输出字符串指示当前使用平台。win->'nt'; Linux->'posix'

os.system("bash command")  # 运行shell命令,直接显示
# 运行shell命令,获取执行结果,有返回值, ret = os.popen("bash command"),print(ret)
os.popen("bash command").read()
os.getcwd()  # 获取当前工作目录,即当前python脚本工作的目录路径
os.chdir("dirname")  # 改变当前脚本工作目录;相当于shell下cd

# os.path
# 返回path规范化的绝对路径os.path.split(path) 将path分割成目录和文件名二元组返回
os.path.abspath('path')
os.path.dirname('path')  # 返回path的目录。其实就是os.path.split(path)的第一个元素
# 返回path最后的文件名。如何path以/或\结尾,那么就会返回空值。即os.path.split(path)的第二个元素
os.path.basename('path')
os.path.exists('path')  # 如果path存在,返回True;如果path不存在,返回False
os.path.isabs('path')  # 如果path是绝对路径,返回True
os.path.isfile('path')  # 如果path是一个存在的文件,返回True。否则返回False
os.path.isdir('path')  # 如果path是一个存在的目录,则返回True。否则返回False
os.path.join('path1[, path2[, ...]]')  # 将多个路径组合后返回,第一个绝对路径之前的参数将被忽略
os.path.getatime('path')  # 返回path所指向的文件或者目录的最后访问时间
os.path.getmtime('path')  # 返回path所指向的文件或者目录的最后修改时间
os.path.getsize('path')  # 返回path的大小,文件夹的大小最多是4096个,循环文件大小,然后加起来就是文件夹的大小
# 程序功能要实现解耦

sys模块

print(sys.argv)           # 命令行参数List,第一个元素是程序本身路径,在执行脚本之前,可以给脚本传一些参数,传进args,终端运用
ret = sys.argv            # 终端参数输入时会传参
name = ret[1]
pwd = ret[2]
if name == 'alex' and pwd == '1234':
    print('success')
else:
    print('error')
# sys.exit()         # 退出程序,正常退出时exit(0),错误退出sys.exit(1),操作系统感知,退出之后,后面的代码不执行,会变灰态
print(sys.version)        # 获取Python解释程序的版本信息
print(sys.path)           # 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
print(sys.platform)       # 返回操作系统平台名称,不准
print(sys.path)   # 记录所有搜索模块的路径,搜不到到上一级去搜,再搜不到到python解释器自带的包里面去搜,返回一个列表
# 列表清空 sys.path.clear()