zoukankan      html  css  js  c++  java
  • 【Python之路】特别篇--Python正则表达式

    正则表达式的基础

      正则表达式并不是Python的一部分。

      正则表达式是用于处理字符串的强大工具,拥有自己独特的语法以及一个独立的处理引擎,效率上可能不如str自带的方法,但功能十分强大。

      得益于这一点,在提供了正则表达式的语言里,正则表达式的语法都是一样的,区别只在于不同的编程语言实现支持的语法数量不同。

      就其本质而言,正则表达式(或 RE)是一种小型的、高度专业化的编程语言,(在Python中)它内嵌在Python中,并通过 re 模块实现。

    元字符

    元字符: . ^ $ * + ? { [ ] | ( )

    . 匹配除了换行符外所有字符 (通配符)

    content = 'Abcdefghijklmnopq'
    test = re.findall(r"b.d",content)
    print(test)
    ['bcd']

    ^ 以....开头

    content = 'Abcdefghijklmnopq'
    test = re.findall(r"^Abcd",content)
    print(test)
    ['Abcd']

    $ 以....结尾

    content = 'Abcdefghijklmnopq'
    test = re.findall(r"nopq$",content)
    print(test)
    ['nopq']

    * 匹配0到多次 {0, }  控制它前面的字符 

    content = 'Abcdefghijklmnopq'
    test = re.findall(r"A.*e",content)
    print(test)
    ['Abcde']

    + 匹配1到多次 {1, }

    content = 'abcdefab111111'
    test = re.findall(r"ab1+",content)
    print(test)
    ['ab111111']

    ?  匹配0到1次 {0,1}

    content = 'abcdefab111111'
    test = re.findall(r"ab1?",content)
    print(test)
    ['ab', 'ab1']

    * +  都是按照贪婪模式进行匹配  非贪婪模式 需要在后面加个?

    content = 'abcdefab111111'
    test = re.findall(r"ab1+?",content)
    print(test)
    ['ab1']
    
    re.search(r"a(d+?)","a2345").group() => a2
    
    re.search(r"a(d*?)","a2345").group() => a
     
    #如果前后均有限定条件 ?不起作用 re.search(r"a(d*?)b","a2345b").group() => a2345b

    ( ) 组  作为一个整体

    content = 'abcdefab111111'
    test = re.findall(r"(ab1)",content)
    print(test)
    ['ab1']

    { }  重复次数自定义

    content = 'abcdefab111111'
    test = re.findall(r"ab1{3,9}",content)
    print(test)
    ['ab111111']

    [ ]  字符集  表示或

          字符集里面元字符会失去意义   除了 -    ^ 3个元字符外

    content1 = 'wwwwwabdxxxxx'
    test1 = re.findall(r"a[bc]d",content1)
    print(test1)
    #['abd']
    
    content2 = 'wwwwwacdxxxxx'
    test2 = re.findall(r"a[bc]d",content2)
    print(test2)
    #['acd']
    
    ***********************************************************************
    
    content = 'wwwwwa.xxxxx'
    test = re.findall(r"a[.]x",content)
    print(test)
    #['a.x']
    
    content = 'wwwww1234xxxxx'
    test = re.findall(r"[1-9]",content)       #1~9的数字
    print(test)
    #['1', '2', '3', '4']
    
    content = 'wwwww1234xxxxx'
    test = re.findall(r"[^1-9]",content)       #非1~9的数字
    print(test)
    #['w', 'w', 'w', 'w', 'w', 'x', 'x', 'x', 'x', 'x']

     作用:

    • 后面跟元字符去除特殊功能
    • 后面跟普通字符实现特殊功能
    • 引用序号对应的字组所匹配的字符串
    test = re.search(r"(alex)(eric)com2","alexericcomeric")
    print(test.group())
    #alexericcomeric

    d  匹配任何十进制数, [0-9]

    D  匹配任何非数字字符 [^0-9]

    s   匹配任何空白字符 [ fv ]

    S  匹配任何非空白字符 [^ fv ]

    w  匹配任何字母数字字符 [a-zA-Z0-9_]

    W 匹配任何非字母数字字符 [^a-zA-Z0-9]

      匹配一个单词边界,单词和空格间的位置  匹配特殊字符(不单止空格)

    content = 'wwwww1234xxxxx'
    test = re.findall(r"d",content)
    print(test)
    # ['1', '2', '3', '4']
    
    content = 'ww&*#$%ww1234xx'
    test = re.findall(r"D",content)
    print(test)
    # ['w', 'w', '&', '*', '#', '$', '%', 'w', 'w', 'x', 'x']
    
    content = 'asdasd   '
    test = re.findall(r"s",content)
    print(test)
    # [' ', ' ', ' ']
    
    content = ' asdasd   '
    test = re.findall(r"S",content)
    print(test)
    # ['a', 's', 'd', 'a', 's', 'd']
    
    content = 'abc123^&*lm-\_'
    test = re.findall(r"w",content)
    print(test)
    # ['a', 'b', 'c', '1', '2', '3', 'l', 'm', '_']
    
    content = 'abc123^&*lm-\_'
    test = re.findall(r"W",content)
    print(test)
    # ['^', '&', '*', '-', '\']
    
    content = 'I like Sooooo'
    test = re.findall(r"like",content)
    print(test)
    # ['like']
    
    *******************************************
    test = re.findall(r"abc","asdasd abc ")
    test = re.findall(r"abc","asdasd abc*")
    print(test)
    # ['abc']
    

    match()

      match()

    # match,从起始位置开始匹配,匹配成功返回一个对象,未匹配成功返回None
      
    match(pattern, string, flags=0)
    # pattern: 正则模型
    # string : 要匹配的字符串
    # falgs  : 匹配模式
     
    # re.I(re.IGNORECASE):    忽略大小写(括号内是完整写法,下同)
    # M(MULTILINE):     多行模式,改变'^'和'$'的行为
    # S(DOTALL):     点任意匹配模式,改变'.'的行为   使 . 匹配包括换行在内的所有字符
    # L(LOCALE):     使预定字符类 w W  B s S 取决于当前区域设定
    # U(UNICODE):  使预定字符类 w W  B s S d D 取决于unicode定义的字符属性
    # X(VERBOSE):   详细模式。这个模式下正则表达式可以是多行,忽略空白字符,并可以加入注释。以下两个正则表达式是等价的:
    
    *************************************
    
    # match对象的方法
    
    .group()	获取匹配到的所有结果
    .groups()	获取模型中匹配到的分组结果	
    .groupdict()	获取模型中匹配到的分组中所有执行了key的组
    .group()       返回被RE匹配的字符串 可以加参数group(1) 组号
    .start()        返回匹配开始的位置
    .end()       返回匹配结束的位置
    .span()         返回一个元组包含的匹配的位置
    # 无分组
    r = re.match("hw+", origin)
    print(r.group())     # 获取匹配到的所有结果
    print(r.groups())    # 获取模型中匹配到的分组结果
    print(r.groupdict()) # 获取模型中匹配到的分组结果
    
    # 有分组
    
    # 为何要有分组?提取匹配成功的指定内容(先匹配成功全部正则,再匹配成功的局部内容提取出来)
    
    r = re.match("h(w+).*(?P<name>d)$", origin)
    print(r.group())     # 获取匹配到的所有结果
    print(r.groups())    # 获取模型中匹配到的分组结果
    print(r.groupdict()) # 获取模型中匹配到的分组中所有执行了key的组
    demo

    search()

      search()

    # search 匹配成功有结果,返回match对象
    # 查看返回结果用.group()
    # search,浏览整个字符串去匹配第一个,未匹配成功返回None
    # search(pattern, string, flags=0)
    # 无分组
    
    r = re.search("aw+", origin)
    print(r.group())     # 获取匹配到的所有结果
    print(r.groups())    # 获取模型中匹配到的分组结果
    print(r.groupdict()) # 获取模型中匹配到的分组结果
    
    # 有分组
    
    r = re.search("a(w+).*(?P<name>d)$", origin)
    print(r.group())     # 获取匹配到的所有结果
    print(r.groups())    # 获取模型中匹配到的分组结果
    print(r.groupdict()) # 获取模型中匹配到的分组中所有执行了key的组
    demo

    findall()

      findall()

    # 优先取组里内容返回!
    # findall,获取非重复的匹配列表;如果有一个组则以列表形式返回,且每一个匹配均是字符串;如果模型中有多个组,则以列表形式返回,且每一个匹配均是元祖;
    # 空的匹配也会包含在结果中
    # findall(pattern, string, flags=0)
     
    data = re.findall("d+wd+",'a2b3c4d5')
    # ['2b3', '4d5']
    # re.findall()	匹配成功一个后,从匹配成功最后位置开始下一次查找
    
    # 空的匹配也会包含在结果中
    data = re.findall("",'a2')
    print(data)
    # ['', '', '']
    
    ***********************************
    
    #有几个括号就取几次
    
    data = re.findall(r'(dasd)*','1asd2asdp3asd3434')
    print(data)
    # ['2asd', '', '3asd', '', '', '', '', '']
    # 贪婪匹配 第一段取到1asd2asd 但最后返回 2asd  取最后一个!
    
    如下:
    a= "alex"
    data = re.findall(r'(w)(w)(w)(w)',a)
    print(data)
    # [('a', 'l', 'e', 'x')]
    
    data = re.findall(r'(w){4}',a)
    print(data)
    # ['x']    => 只是执行了4次,返回还是按一个括号算,取最后匹配的一项
    
    ***********************************
    
    test = re.findall("www.(baidu|laonanhai).com","asdsa www.baidu.com")
    print(test)
    # ['baidu']
     
    添加 ?: 去掉优先权
    test = re.findall("www.(?:baidu|laonanhai).com","asdsa www.baidu.com")
    print(test)
    # ['www.baidu.com']
    # 无分组
    r = re.findall("aw+",origin)
    print(r)
    
    # 有分组
    origin = "hello alex bcd abcd lge acd 19"
    r = re.findall("a((w*)c)(d)", origin)
    print(r)
    # [('bc', 'b', 'd'), ('c', '', 'd')]
    demo

    sub()

      sub()

    # sub,替换匹配成功的指定位置字符串
     
    sub(pattern, repl, string, count=0, flags=0)
    # pattern: 正则模型
    # repl   : 要替换的字符串或可执行对象
    # string : 要匹配的字符串
    # count  : 指定匹配个数
    # flags  : 匹配模式
    
    test = re.sub("g.t","have","I get A, I got B , I gut C")
    print(test)
    #I have A, I have B , I have C
    
    ********************************************
    
    #subn    最后还返回一个替换次数
    
    origin = "ale4 xc 19"
    data,counts = re.subn("d+","KKK",origin)
    print(data,counts)
    # aleKKK xc KKK 2

    compile()

      compile()

    regex = re.compile(r"w*oow*")
    text = " JGood is ,he is cool"
    data = regex.findall(text)
    print(data)
    #['JGood', 'cool']
    

    split()

      split()

    # split,根据正则匹配分割字符串
    split(pattern, string, maxsplit=0, flags=0)
    
    # pattern: 正则模型
    # string : 要匹配的字符串
    # maxsplit:指定分割个数
    # flags  : 匹配模式
    
    *****************************************
    # 有分组情况下, 把分割的项也添加进去
    
    origin = "hello alex bcd alex lge alex acd 19"
    r1 = re.split("(alex)", origin, 1)
    print(r1)
    # ['hello ', 'alex', ' bcd alex lge alex acd 19']
    
    r2 = re.split("(al(ex))", origin, 1)
    print(r2)
    # ['hello ', 'alex', 'ex', ' bcd alex lge alex acd 19']
    
    *****************************************
    
    p = re.compile(r"d+")
    test = p.split("one1two2three3four4")
    print(test)
    # ['one', 'two', 'three', 'four', '']
    # 末尾有空字符串
     
    => one,two2three3four4 => ['one']  two,three3four4 => ..
     
    test = re.split('[bc]','abcd')
    print(test)
    # ['a', '', 'd']
    # 无分组
    origin = "hello alex bcd alex lge alex acd 19"
    r = re.split("alex", origin, 1)
    print(r)
    
    # 有分组
            
    origin = "hello alex bcd alex lge alex acd 19"
    r1 = re.split("(alex)", origin, 1)
    print(r1)
    r2 = re.split("(al(ex))", origin, 1)
    print(r2)
    demo

    finditer()

      finditer()

    # 返回结果为迭代对象
    
    p = re.compile(r"d+")
    w = p.finditer(' 1 drum44ers druming , 11 ... 10 ...')
    for match in w:
        print(match.group(),match.span())
    
    # 1 (1, 2)
    # 44 (7, 9)
    # 11 (23, 25)
    # 10 (30, 32)

    反斜杠的困扰

    与大多数编程语言相同,正则表达式里使用""作为转义字符,这就可能造成反斜杠困扰。

    假如你需要匹配文本中的字符"",那么使用编程语言表示的正则表达式里将需要4个反斜杠"\\"

    前两个和后两个分别用于在编程语言里转义成反斜杠,转换成两个反斜杠后再在正则表达式里转义成一个反斜杠。

    Python里的原生字符串很好地解决了这个问题,这个例子中的正则表达式可以使用r"\"表示。

    同样,匹配一个数字的"\d"可以写成r"d"。有了原生字符串,你再也不用担心是不是漏写了反斜杠,写出来的表达式也更直观。

    常用正则表达式

    # IP:
    ^(25[0-5]|2[0-4]d|[0-1]?d?d)(.(25[0-5]|2[0-4]d|[0-1]?d?d)){3}$
    
    # 手机号:
    ^1[3|4|5|8][0-9]d{8}$
    
    # 邮箱:
    [a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(.[a-zA-Z0-9_-]+)+
    

    练习题:计算器

    #!/usr/bin/env python
    # -*-coding:utf-8 -*-
    
    import re
    
    # 加减运算:
    def add_sub(origin):
        '''
        进行加减运算,按+ - 符号拆分,
        :param origin: 传入的表达式
        :return:
        '''
        data = re.split('([+-]{1})', origin)
        # 预处理 把 '' 转换成 '0'
        for i in range(len(data)):
            if data[i].strip() == '':
                data[i] = '0'
        # 预处理 负负得正 情况:
        for i in range(len(data)):
            if data[i].strip() == '0' and i != 0 :
                if data[i-1].strip() == '-':
                    data[i+1] = '+'
    
        # 计算开始:
        total = 0
        # flag = 0 默认加号  1为减号
        flag = 0
        for i in range(len(data)):
            if data[i].strip() == '-':
                flag = 1
                continue
            elif data[i].strip() == '+':
                flag = 0
                continue
            elif flag == 0 :
                total += float(data[i].strip()) if '.'in data[i] else int(data[i].strip())
            elif flag == 1 :
                total -= float(data[i].strip()) if '.'in data[i] else int(data[i].strip())
    
        return total
    
    
    # 计算乘除,乘方运算:
    def plus_div(origin):
        '''
        按前后顺序拆分,需要进行 乘除,乘方 运算的地方,获得式子,计算出结果,顶替回原来位置,循环此步骤,只剩加减法,再把只剩加减法的式子传入add_sub()计算
        :param origin: 传入的表达式
        :return:
        '''
        while True:
            data = re.split('([-]?d+.?d*s*(?:[*/]|**)s*[-]?d+.?d*)',origin,1)
            # 判断表达式是否只剩加减运算 , 传入 add_sub() 进行加减法的计算
            if len(data) ==1:
                result = add_sub(data[0])
                return result
                break
            # 判断表达式是否还包含 乘除,乘方 符号 ,如果包含,继续拆分运算,最终获得只剩加减的式子
            elif len(data) ==3:
                counts = data[1]    # 获得匹配出的 运算符号 * / 或 **
                before, content, after = data
            else:
                print('Error')
    
            # 判断需要进行哪种运算,
            if '**' in counts:
                num = counts.split('**')
                left = float(num[0].strip()) if '.'in num[0] else int(num[0].strip())
                right = float(num[1].strip()) if '.' in num[1] else int(num[1].strip())
                total = left ** right
    
            elif '/' in counts:
                num = counts.split('/')
                left = float(num[0].strip()) if '.'in num[0] else int(num[0].strip())
                right = float(num[1].strip()) if '.' in num[1] else int(num[1].strip())
                total = left / right
    
            elif '*' in counts:
                num = counts.split('*')
                left = float(num[0].strip()) if '.'in num[0] else int(num[0].strip())
                right = float(num[1].strip()) if '.' in num[1] else int(num[1].strip())
                total = left * right
    
            # 此时只进行了表达式内的一次乘除,乘方运算, 计算结果拼接顶替原来的位置,继续循环直到只剩加减法
            origin = before + str(total) + after
    
    
    def count(origin):
        """
        1.一步一步拆分括号,每获得一次 最里层的括号表达式 ,就传入plus_div()函数 进行 该表达式的所有乘除运算,再进行加减运算,返回该表达式最终结果,
        拼接回原表达式,替换回括号位置.再循环寻找下一个括号内表达式,直到所有括号的表达式计算完毕,最终只剩一条只包含单纯的乘除加减运算的表达式.
    
        :param origin: 需要计算的表达式
        :return:
        """
        while True:
            # 拆分() 获得最里层的括号!
            data = re.split('(([^()]+))',origin,1)
            if len(data) == 3:
                before,content,after = data
                result = plus_div(content)      # () 里面的表达式传入 plus_div 进行计算
                origin = before + str(result) + after   # 把计算结果 拼接回原来括号的位置. 进行下一次括号寻找!
            else:
                # 当只剩一条只包含单纯的乘除加减运算的表达式时,
                result = plus_div(data[0])
                return result
                break
    
    
    origin = " 6 * 2 + ( 4 -3.5 + 1 * 91 + (-1 +2) * 5 -5 ) / 2 + 2 ** 9"
    result = count(origin)
    
    
    print('表达式: ' + origin)
    print('我的计算结果 :
    ' + str(result))
    print('eval计算结果: 
    '+ str(eval(origin)))
    View Code
  • 相关阅读:
    [NHibernate]条件查询Criteria Query
    [JQuery]用InsertAfter实现图片走马灯展示效果
    [NHibernate]HQL查询
    [NHibernate]基本配置与测试
    [HTML/CSS]margin属性用法
    [HTML/CSS]盒子模型,块级元素和行内元素
    [Asp.net MVC]Asp.net MVC5系列——布局视图
    [c#基础]值类型和引用类型的Equals,==的区别
    用中间件实现读负载均衡的数据库群集
    论数据库连接池对中间件性能的重要性
  • 原文地址:https://www.cnblogs.com/5poi/p/6103711.html
Copyright © 2011-2022 走看看