• day4 迭代器&生成器&递归&json&正则


    1.迭代器&生成器

    2.装饰器

    1. 基本装饰器
    2. 多参数装饰器

    3.递归

    4.Json & pickle 数据序列化  --day5模块学习

    5.算法基础:二分查找、二维数组转换

    6.正则表达式

    迭代器

    迭代器是访问集合元素的一种方式。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退。另外,迭代器的一大优点是不要求事先准备好整个迭代过程中所有的元素。迭代器仅仅在迭代到某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者被销毁。这个特点使得它特别适合用于遍历一些巨大的或是无限的集合,比如几个G的文件

    特点:

    访问者不需要关心迭代器内部的结构,仅需通过next()方法不断去取下一个内容

    1. 不能随机访问集合中的某个值 ,只能从头到尾依次访问
    2. 访问到一半时不能往回退
    3. 便于循环比较大的数据集合,节省内存

    生成一个迭代器:

    a = iter([1,2,3])
    a
    <list_iterator object at 0x101402630>
    >>> a.__next__()
    1
    >>> a.__next__()
    2
    >>> a.__next__()
    3
    >>> a.__next__()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    StopIteration
    View Code

    列表生成式

    现在有个需求, 有列表 [0,1,2,3,4,5,6,7,8,9],要求你把列表里面的每个值加1,你怎么实现呢?

    方法一,

    info = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    b = []
    # for index,i in enumerate(info):
    #     print(i+1)
    #     b.append(i+1)
    # print(b)
    for index,i in enumerate(info):
        info[index] +=1
    print(info)
    View Code

    方法二,

    info = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    a = map(lambda x:x+1,info)
    print(a)
    for i in a:
        print(i)
    View Code

    方法三,

    info = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    a = [i+1 for i in range(10)]
    print(a)
    View Code

    生成器generator

    定义:一个函数调用时返回一个迭代器,那这个函数就叫做生成器(generator),如果函数中包含yield语法,那这个函数就会变成生成器

      通过列表生成式,我们可以直接创建一个列表,但是,受到内存限制,列表容量肯定是有限的,而且创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。

      所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间,在Python中,这种一边循环一边计算的机制,称为生成器:generator

      生成器是一个特殊的程序,可以被用作控制循环的迭代行为,python中生成器是迭代器的一种,使用yield返回值函数,每次调用yield会暂停,而可以使用next()函数和send()函数恢复生成器。

      生成器类似于返回值为数组的一个函数,这个函数可以接受参数,可以被调用,但是,不同于一般的函数会一次性返回包括了所有数值的数组,生成器一次只能产生一个值,这样消耗的内存数量将大大减小,而且允许调用函数可以很快的处理前几个返回值,因此生成器看起来像是一个函数,但是表现得却像是迭代器

    python中的生成器

    要创建一个generator,有很多种方法,第一种方法很简单,只有把一个列表生成式的[]中括号改为()小括号,就创建一个generator:

    #列表生成式
    lis = [x*x for x in range(10)]
    print(lis)
    #生成器
    generator_ex = (x*x for x in range(10))
    print(generator_ex)
     
    结果:
    [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
    <generator object <genexpr> at 0x000002A4CBF9EBA0>
    View Code

      那么创建list和generator_ex,的区别是什么呢?从表面看就是[  ]和(),但是结果却不一样,一个打印出来是列表(因为是列表生成式),而第二个打印出来却是<generator object <genexpr> at 0x000002A4CBF9EBA0>,那么如何打印出来generator_ex的每一个元素呢?

      如果要一个个打印出来,可以通过next()函数获得generator的下一个返回值:

    generator保存的是算法,每次调用next(generaotr_ex)就计算出他的下一个元素的值,直到计算出最后一个元素,没有更多的元素时,抛出StopIteration的错误,而且上面这样不断调用是一个不好的习惯,正确的方法是使用for循环,因为generator也是可迭代对象:

    所以我们创建一个generator后,基本上永远不会调用next(),而是通过for循环来迭代,并且不需要关心StopIteration的错误,generator非常强大,如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。

    比如著名的斐波那契数列,除第一个和第二个数外,任何一个数都可以由前两个相加得到:

    #fibonacci数列
    def fib(max):
        n,a,b =0,0,1
        while n < max:
            a,b =b,a+b
            n = n+1
            print(a)
        return 'done'
     
    a = fib(10)
    print(fib(10))
    View Code

    a,b = b ,a+b  其实相当于 t =a+b ,a =b ,b =t  ,所以不必写显示写出临时变量t,就可以输出斐波那契数列的前N个数字。

    仔细观察,可以看出,fib函数实际上是定义了斐波拉契数列的推算规则,可以从第一个元素开始,推算出后续任意的元素,这种逻辑其实非常类似generator。

    也就是说上面的函数也可以用generator来实现,上面我们发现,print(b)每次函数运行都要打印,占内存,所以为了不占内存,我们也可以使用生成器,这里叫yield。如下:

    def fib(max):
        n,a,b =0,0,1
        while n < max:
            yield b
            a,b =b,a+b
            n = n+1
        return 'done'
     
    a = fib(10)
    print(fib(10))
    View Code

    但是返回的不再是一个值,而是一个生成器,和上面的例子一样,大家可以看一下结果:

    <generator object fib at 0x000001C03AC34FC0>
    那么这样就不占内存了,这里说一下generator和函数的执行流程,函数是顺序执行的,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次被next()调用时候从上次的返回yield语句处急需执行,也就是用多少,取多少,不占内存。
     
    def fib(max):
        n,a,b =0,0,1
        while n < max:
            yield b
            a,b =b,a+b
            n = n+1
        return 'done'
     
    a = fib(10)
    print(fib(10))
    print(a.__next__())
    print(a.__next__())
    print(a.__next__())
    print("可以顺便干其他事情")
    print(a.__next__())
    print(a.__next__())
     
    结果:
    <generator object fib at 0x0000023A21A34FC0>
    1
    1
    2
    可以顺便干其他事情
    3
    5
    

    在上面fib的例子,我们在循环过程中不断调用yield,就会不断中断。当然要给循环设置一个条件来退出循环,不然就会产生一个无限数列出来。同样的,把函数改成generator后,我们基本上从来不会用next()来获取下一个返回值,而是直接使用for循环来迭代:

    def fib(max):
        n,a,b =0,0,1
        while n < max:
            yield b
            a,b =b,a+b
            n = n+1
        return 'done'
    for i in fib(6):
        print(i)
         
    结果:
    1
    1
    2
    3
    5
    8
    

     但是用for循环调用generator时,发现拿不到generator的return语句的返回值。如果拿不到返回值,那么就会报错,所以为了不让报错,就要进行异常处理,拿到返回值,如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的value中:

    def fib(max):
        n,a,b =0,0,1
        while n < max:
            yield b
            a,b =b,a+b
            n = n+1
        return 'done'
    g = fib(6)
    while True:
        try:
            x = next(g)
            print('generator: ',x)
        except StopIteration as e:
            print("生成器返回值:",e.value)
            break
     
    结果:
    generator:  1
    generator:  1
    generator:  2
    generator:  3
    generator:  5
    generator:  8
    生成器返回值: done
    

     还可以通过yield实现在单线程的情况下实现并发运算的效果

    import time
    def consumer(name):
        print("%s 准备学习啦!" %name)
        while True:
           lesson = yield
     
           print("开始[%s]了,[%s]老师来讲课了!" %(lesson,name))
     
     
    def producer(name):
        c = consumer('A')
        c2 = consumer('B')
        c.__next__()
        c2.__next__()
        print("同学们开始上课 了!")
        for i in range(6):
            time.sleep(1)
            print("到了两个同学!")
            c.send(i)
            c2.send(i)
    producer("felix")
     
    结果:
    A 准备学习啦!
    B 准备学习啦!
    同学们开始上课 了!
    到了两个同学!
    开始[0]了,[A]老师来讲课了!
    开始[0]了,[B]老师来讲课了!
    到了两个同学!
    开始[1]了,[A]老师来讲课了!
    开始[1]了,[B]老师来讲课了!
    到了两个同学!
    开始[2]了,[A]老师来讲课了!
    开始[2]了,[B]老师来讲课了!
    到了两个同学!
    开始[3]了,[A]老师来讲课了!
    开始[3]了,[B]老师来讲课了!
    到了两个同学!
    开始[4]了,[A]老师来讲课了!
    开始[4]了,[B]老师来讲课了!
    到了两个同学!
    开始[5]了,[A]老师来讲课了!
    开始[5]了,[B]老师来讲课了!
    View Code

    由上面的例子我么可以发现,python提供了两种基本的方式

       生成器函数:也是用def定义的,利用关键字yield一次性返回一个结果,阻塞,重新开始

       生成器表达式:返回一个对象,这个对象只有在需要的时候才产生结果

    ——生成器函数

    为什么叫生成器函数?因为它随着时间的推移生成了一个数值队列。一般的函数在执行完毕之后会返回一个值然后退出,但是生成器函数会自动挂起,然后重新拾起急需执行,他会利用yield关键字关起函数,给调用者返回一个值,同时保留了当前的足够多的状态,可以使函数继续执行,生成器和迭代协议是密切相关的,迭代器都有一个__next__()__成员方法,这个方法要么返回迭代的下一项,要买引起异常结束迭代。

     函数有了yield之后,函数名+()就变成了生成器
    # return在生成器中代表生成器的中止,直接报错
    # next的作用是唤醒并继续执行
    # send的作用是唤醒并继续执行,发送一个信息到生成器内部
    '''生成器'''
     
    def create_counter(n):
        print("create_counter")
        while True:
            yield n
            print("increment n")
            n +=1
     
    gen = create_counter(2)
    print(gen)
    print(next(gen))
    print(next(gen))
     
    结果:
    <generator object create_counter at 0x0000023A1694A938>
    create_counter
    2
    increment n
    3
    Process finished with exit code 0
    View Code

    ——生成器表达式

    生成器表达式来源于迭代和列表解析的组合,生成器和列表解析类似,但是它使用尖括号而不是方括号

    >>> # 列表解析生成列表
    >>> [ x ** 3 for x in range(5)]
    [0, 1, 8, 27, 64]
    >>>
    >>> # 生成器表达式
    >>> (x ** 3 for x in range(5))
    <generator object <genexpr> at 0x000000000315F678>
    >>> # 两者之间转换
    >>> list(x ** 3 for x in range(5))
    [0, 1, 8, 27, 64]
    View Code

      一个迭代既可以被写成生成器函数,也可以被协程生成器表达式,均支持自动和手动迭代。而且这些生成器只支持一个active迭代,也就是说生成器的迭代器就是生成器本身。

    迭代器(迭代就是循环)

      迭代器包含有next方法的实现,在正确的范围内返回期待的数据以及超出范围后能够抛出StopIteration的错误停止迭代。

    我们已经知道,可以直接作用于for循环的数据类型有以下几种:

      一类是集合数据类型,如list,tuple,dict,set,str等

      一类是generator,包括生成器和带yield的generator function

    这些可以直接作用于for 循环的对象统称为可迭代对象:Iterable,可以使用isinstance()判断一个对象是否为可Iterable对象

    >>> from collections import Iterable
    >>> isinstance([], Iterable)
    True
    >>> isinstance({}, Iterable)
    True
    >>> isinstance('abc', Iterable)
    True
    >>> isinstance((x for x in range(10)), Iterable)
    True
    >>> isinstance(100, Iterable)
    False
    View Code

      而生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。

    所以这里讲一下迭代器

    一个实现了iter方法的对象是可迭代的,一个实现next方法并且是可迭代的对象是迭代器。

    可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。

    所以一个实现了iter方法和next方法的对象就是迭代器。

    可以使用isinstance()判断一个对象是否是Iterator对象:

    >>> from collections import Iterator
    >>> isinstance((x for x in range(10)), Iterator)
    True
    >>> isinstance([], Iterator)
    False
    >>> isinstance({}, Iterator)
    False
    >>> isinstance('abc', Iterator)
    False
    View Code

    生成器都是Iterator对象,但listdictstr虽然是Iterable(可迭代对象),却不是Iterator(迭代器)

    listdictstrIterable变成Iterator可以使用iter()函数

    >>> isinstance(iter([]), Iterator)
    True
    >>> isinstance(iter('abc'), Iterator)
    True
    View Code

    你可能会问,为什么listdictstr等数据类型不是Iterator

    这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。

    Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。

    f=open('test.txt') #文件是可迭代对象,是迭代器
    from collections import Iterator  #迭代器
    from collections import Iterable  #可迭代对象
     

    小结:

    • 凡是可作用于for循环的对象都是Iterable类型;
    • 凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;
    • 集合数据类型如listdictstr等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。

    Python3的for循环本质上就是通过不断调用next()函数实现的,例如:

    for x in [1, 2, 3, 4, 5]:
        pass
    
    #实际上完全等价于
    # 首先获得Iterator对象:
    it = iter([1, 2, 3, 4, 5])
    # 循环:
    while True:
        try:
            # 获得下一个值:
            x = next(it)
        except StopIteration:
            # 遇到StopIteration就退出循环
            break
    View Code

    对yield的总结

      (1)通常的for..in...循环中,in后面是一个数组,这个数组就是一个可迭代对象,类似的还有链表,字符串,文件。他可以是a = [1,2,3],也可以是a = [x*x for x in range(3)]。

    它的缺点也很明显,就是所有数据都在内存里面,如果有海量的数据,将会非常耗内存。

      (2)生成器是可以迭代的,但是只可以读取它一次。因为用的时候才生成,比如a = (x*x for x in range(3))。!!!!注意这里是小括号而不是方括号。

      (3)生成器(generator)能够迭代的关键是他有next()方法,工作原理就是通过重复调用next()方法,直到捕获一个异常。

      (4)带有yield的函数不再是一个普通的函数,而是一个生成器generator,可用于迭代

      (5)yield是一个类似return 的关键字,迭代一次遇到yield的时候就返回yield后面或者右面的值。而且下一次迭代的时候,从上一次迭代遇到的yield后面的代码开始执行

      (6)yield就是return返回的一个值,并且记住这个返回的位置。下一次迭代就从这个位置开始。

      (7)带有yield的函数不仅仅是只用于for循环,而且可用于某个函数的参数,只要这个函数的参数也允许迭代参数。

      (8)send()和next()的区别就在于send可传递参数给yield表达式,这时候传递的参数就会作为yield表达式的值,而yield的参数是返回给调用者的值,也就是说send可以强行修改上一个yield表达式值。

      (9)send()和next()都有返回值,他们的返回值是当前迭代遇到的yield的时候,yield后面表达式的值,其实就是当前迭代yield后面的参数。

      (10)第一次调用时候必须先next()或send(),否则会报错,send后之所以为None是因为这时候没有上一个yield,所以也可以认为next()等同于send(None)

    2.装饰器

    必备知识点:
    #### 第一波 ####
    def foo():
        print 'foo'
     
    foo     #表示是函数
    foo()   #表示执行foo函数
     
    #### 第二波 ####
    def foo():
        print 'foo'
     
    foo = lambda x: x + 1
     
    foo()   # 执行下面的lambda表达式,而不再是原来的foo函数,因为函数 foo 被重新定义了
    View Code

    遵循开发封闭原则,封闭:已实现的功能代码块,开放:对扩展开发,在原有的功能模块上加上认证:

    def w1(func):
        def inner():
            # 验证1
            # 验证2
            # 验证3
            return func()
        return inner
     
    @w1
    def f1():
        print 'f1'
    @w1
    def f2():
        print 'f2'
    @w1
    def f3():
        print 'f3'
    @w1
    def f4():
        print 'f4'
    View Code

    @函数名 是python的一种语法糖

    如上例@w1内部会执行一下操作:

    • 执行w1函数,并将 @w1 下面的 函数 作为w1函数的参数,即:@w1 等价于 w1(f1)
      所以,内部就会去执行:
          def inner:
              #验证
              return f1()   # func是参数,此时 func 等于 f1
          return inner     # 返回的 inner,inner代表的是函数,非执行函数
      其实就是将原来的 f1 函数塞进另外一个函数中
    • 将执行完的 w1 函数返回值赋值给@w1下面的函数的函数名
      w1函数的返回值是:
         def inner:
              #验证
              return 原来f1()  # 此处的 f1 表示原来的f1函数
      然后,将此返回值再重新赋值给 f1,即:
      新f1 = def inner:
                  #验证
                  return 原来f1() 
      所以,以后业务部门想要执行 f1 函数时,就会执行 新f1 函数,在 新f1 函数内部先执行验证,再执行原来的f1函数,然后将 原来f1 函数的返回值 返回给了业务调用者。
      如此一来, 即执行了验证的功能,又执行了原来f1函数的内容,并将原f1函数返回值 返回给业务调用着

    处理多个参数的函数的装饰器

    def w1(func):
        def inner(*args,**kwargs):
            # 验证1
            # 验证2
            # 验证3
            return func(*args,**kwargs)
        return inner
     
    @w1
    def f1(arg1,arg2,arg3):
        print 'f1'
    View Code

    3.递归

    递归算法是一种直接或者间接地调用自身算法的过程。在计算机编写程序中,递归算法对解决一大类问题是十分有效的,它往往使算法的描述简洁而且易于理解。
    递归算法解决问题的特点:
    (1) 递归就是在过程或函数里调用自身。
    (2) 在使用递归策略时,必须有一个明确的递归结束条件,称为递归出口。
    (3) 递归算法解题通常显得很简洁,但递归算法解题的运行效率较低。所以一般不提倡用递归算法设计程序。
    (4) 在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储。递归次数过多容易造成栈溢出等。所以一般不提倡用递归算法设计程序。

     要求

    递归算法所体现的“重复”一般有三个要求:
    一是每次调用在规模上都有所缩小(通常是减半);
    二是相邻两次重复之间有紧密的联系,前一次要为后一次做准备(通常前一次的输出就作为后一次的输入);
    三是在问题的规模极小时必须用直接给出解答而不再进行递归调用,因而每次递归调用都是有条件的(以规模未达到直接解答的大小为条件),无条件递归调用将会成为死循环而不能正常结束。

     

    4.json 和 pickle

    用于序列化的两个模块

    • json,用于字符串 和 python数据类型间进行转换
    • pickle,用于python特有的类型 和 python的数据类型间进行转换

    Json模块提供了四个功能:dumps、dump、loads、load

    pickle模块提供了四个功能:dumps、dump、loads、load

    5.算法基础

    实现

    1. 通过递归实现2分查找
    def binary_search(data_list,find_num):
        mid_pos = int(len(data_list) /2 ) #find the middle position of the list
        mid_val = data_list[mid_pos] # get the value by it's position
        print(data_list)
        if len(data_list) >1:
            if mid_val > find_num: # means the find_num is in left hand of mid_val
                print("[%s] should be in left of [%s]" %(find_num,mid_val))
                binary_search(data_list[:mid_pos],find_num)
            elif mid_val < find_num: # means the find_num is in the right hand of mid_val
                print("[%s] should be in right of [%s]" %(find_num,mid_val))
                binary_search(data_list[mid_pos:],find_num)
            else: # means the mid_val == find_num
                print("Find ", find_num)
     
        else:
            print("cannot find [%s] in data_list" %find_num)
     
    if __name__ == '__main__':
        primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
        binary_search(primes,67)
    View Code

    2.要求:生成一个4*4的2维数组并将其顺时针旋转90度

    #!_*_coding:utf-8_*_
     
     
    array=[[col for col in range(5)] for row in range(5)] #初始化一个4*4数组
    #array=[[col for col in 'abcde'] for row in range(5)]
     
    for row in array: #旋转前先看看数组长啥样
        print(row)
     
    print('-------------')
    for i,row in enumerate(array):
     
        for index in range(i,len(row)):
            tmp = array[index][i] #get each rows' data by column's index
            array[index][i] = array[i][index] #
            print tmp,array[i][index]  #= tmp
            array[i][index] = tmp
        for r in array:
            print(r)
     
        print('--one big loop --')    
    View Code

    3.冒泡排序,将一个不规则的数组按从小到大的顺序进行排序

    data = [10,4,33,21,54,3,8,11,5,22,2,1,17,13,6]
     
    print("before sort:",data)
     
    previous = data[0]
    for j in range(len(data)):
        tmp = 0
        for i in range(len(data)-1):
            if data[i] > data[i+1]:
                tmp=data[i]
                data[i] = data[i+1]
                data[i+1] = tmp
        print(data)
     
    print("after sort:",data)
    View Code
    时间复杂度 
    (1)时间频度
     一个算法执行所耗费的时间,从理论上是不能算出来的,必须上机运行测试才能知道。但我们不可能也没有必要对每个算法都上机测试,只需知道哪个算法花费的时间多,哪个算法花费的时间少就可以了。并且一个算法花费的时间与算法中语句的执行次数成正比例,哪个算法中语句执行次数多,它花费时间就多。一个算法中的语句执行次数称为语句频度或时间频度。记为T(n)。
    (2)时间复杂度 在刚才提到的时间频度中,n称为问题的规模,当n不断变化时,时间频度T(n)也会不断变化。但有时我们想知道它变化时呈现什么规律。为此,我们引入时间复杂度概念。 一般情况下,算法中基本操作重复执行的次数是问题规模n的某个函数,用T(n)表示,若有某个辅助函数f(n),使得当n趋近于无穷大时,T(n)/f(n)的极限值为不等于零的常数,则称f(n)是T(n)的同数量级函数。记作T(n)=O(f(n)),O(f(n)) 为算法的渐进时间复杂度,简称时间复杂度。

    6.正则表达式

    语法:

    import re #导入模块名
     
    p = re.compile("^[0-9]")  #生成要匹配的正则对象 , ^代表从开头匹配,[0-9]代表匹配0至9的任意一个数字, 所以这里的意思是对传进来的字符串进行匹配,如果这个字符串的开头第一个字符是数字,就代表匹配上了
     
    m = p.match('14534Abc')   #按上面生成的正则对象 去匹配 字符串, 如果能匹配成功,这个m就会有值, 否则m为None<br><br>if m: #不为空代表匹配上了
      print(m.group())    #m.group()返回匹配上的结果,此处为1,因为匹配上的是1这个字符<br>else:<br>  print("doesn't match.")<br>
    View Code

    可合并成一行

    m = p.match("^[0-9]",'14534Abc')
    效果是一样的,区别在于,第一种方式是提前对要匹配的格式进行了编译(对匹配公式进行解析),这样再去匹配的时候就不用在编译匹配的格式,第2种简写是每次匹配的时候 都 要进行一次匹配公式的编译,所以,如果你需要从一个5w行的文件中匹配出所有以数字开头的行,建议先把正则公式进行编译再匹配,这样速度会快点。
    匹配格式
    模式描述
    ^ 匹配字符串的开头
    $ 匹配字符串的末尾。
    . 匹配任意字符,除了换行符,当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符。
    [...] 用来表示一组字符,单独列出:[amk] 匹配 'a','m'或'k'
    [^...] 不在[]中的字符:[^abc] 匹配除了a,b,c之外的字符。
    re* 匹配0个或多个的表达式。
    re+ 匹配1个或多个的表达式。
    re? 匹配0个或1个由前面的正则表达式定义的片段,非贪婪方式
    re{ n}  
    re{ n,} 精确匹配n个前面表达式。
    re{ n, m} 匹配 n 到 m 次由前面的正则表达式定义的片段,贪婪方式
    a| b 匹配a或b
    (re) G匹配括号内的表达式,也表示一个组
    (?imx) 正则表达式包含三种可选标志:i, m, 或 x 。只影响括号中的区域。
    (?-imx) 正则表达式关闭 i, m, 或 x 可选标志。只影响括号中的区域。
    (?: re) 类似 (...), 但是不表示一个组
    (?imx: re) 在括号中使用i, m, 或 x 可选标志
    (?-imx: re) 在括号中不使用i, m, 或 x 可选标志
    (?#...) 注释.
    (?= re) 前向肯定界定符。如果所含正则表达式,以 ... 表示,在当前位置成功匹配时成功,否则失败。但一旦所含表达式已经尝试,匹配引擎根本没有提高;模式的剩余部分还要尝试界定符的右边。
    (?! re) 前向否定界定符。与肯定界定符相反;当所含表达式不能在字符串当前位置匹配时成功
    (?> re) 匹配的独立模式,省去回溯。
    w 匹配字母数字
    W 匹配非字母数字
    s 匹配任意空白字符,等价于 [ f].
    S 匹配任意非空字符
    d 匹配任意数字,等价于 [0-9].
    D 匹配任意非数字
    A 匹配字符串开始
     匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串。c
    z 匹配字符串结束
    G 匹配最后匹配完成的位置。
     匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。
    B 匹配非单词边界。'erB' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。
    , , 等. 匹配一个换行符。匹配一个制表符。等
    1...9 匹配第n个分组的子表达式。
    10 匹配第n个分组的子表达式,如果它经匹配。否则指的是八进制字符码的表达式。

    正则表达式常用5种操作

    re.match(pattern, string)     # 从头匹配

    re.search(pattern, string)    # 匹配整个字符串,直到找到一个匹配

    re.split()            # 将匹配到的格式当做分割点对字符串分割成列表

    >>>m = re.split("[0-9]", "felix1rain2jack3helen rachel8")
    >>>print(m)
    输出: ['felix', 'rain', 'jack', 'helen rachel', '']
    View Code
    re.findall()          # 找到所有要匹配的字符并返回列表格式
    >>>m = re.findall("[0-9]", "felix1rain2jack3helen rachel8")
    >>>print(m)<br>
    输出:['1', '2', '3', '8']
    View Code
    re.sub(pattern, repl, string, count,flag)    # 替换匹配到的字符
    m=re.sub("[0-9]","|", "felix1rain2jack3helen rachel8",count=2 )
    print(m)
    输出:felix|rain|jack3helen rachel8  
    View Code

    正则表达式实例

    字符匹配

    实例描述
    python 匹配 "python".

     

    字符类

    实例描述
    [Pp]ython 匹配 "Python" 或 "python"
    rub[ye] 匹配 "ruby" 或 "rube"
    [aeiou] 匹配中括号内的任意一个字母
    [0-9] 匹配任何数字。类似于 [0123456789]
    [a-z] 匹配任何小写字母
    [A-Z] 匹配任何大写字母
    [a-zA-Z0-9] 匹配任何字母及数字
    [^aeiou] 除了aeiou字母以外的所有字符
    [^0-9] 匹配除了数字外的字符

    特殊字符类

    实例描述
    . 匹配除 " " 之外的任何单个字符。要匹配包括 ' ' 在内的任何字符,请使用象 '[. ]' 的模式。
    d 匹配一个数字字符。等价于 [0-9]。
    D 匹配一个非数字字符。等价于 [^0-9]。
    s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ f v]。
    S 匹配任何非空白字符。等价于 [^ f v]。
    w 匹配包括下划线的任何单词字符。等价于'[A-Za-z0-9_]'。
    W 匹配任何非单词字符。等价于 '[^A-Za-z0-9_]'。

    re.match与re.search的区别

    re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配。


                                                                  
     
  • 相关阅读:
    mvc:三
    mvc:二
    Linq分组,linq方法分组
    Linq 中按照多个值进行分组(GroupBy)
    Photoshop 字体
    报表Reporting S而vice是 错误的解决
    1*书籍装帧
    photoshop 魔术橡皮擦
    Photoshop 钢笔 双窗口显示
    数字格式化
  • 原文地址:https://www.cnblogs.com/xiefugui/p/11737911.html
Copyright © 2020-2023  润新知