美文网首页
19 正则表达式和re模块

19 正则表达式和re模块

作者: 代码小小白 | 来源:发表于2020-09-14 17:53 被阅读0次
    正则表达式规则:
    一、字符组:[]

    ① 描述的是一个位置上能出现的所有可能性,一个括号只匹配一个字符的内容
    ②可以接受范围,是根据asc-ii码的范围进行匹配,只能从小到大,反过来就报错
    例如:
    [abc] 匹配a或b或c
    [0-9] 匹配0到9中的一个数字
    [a-z] 所有的小写字母
    [A-Z] 所有的大写字母
    [a-zA-Z] 大小写
    [0-9a-zA-Z_] 数字字母下划线

    二、其他元字符

    \d 任意数字
    \D 任意非数字
    \s 空白
    \S 非空白
    \w 数字字母下划线
    \W 非数字字母下划线
    \t tab键
    \n 换行符
    . 匹配除了换行符之外的所有
    [^] 非
    ^ 匹配字符串的开头
    $ 匹配字符串的结尾:

    例:判断用户注册的手机号是否合法,必须要有开头和结尾,不然1390000000113900000002也是合法的
     ^1[3-9]\d{9}$
    

    | 或 ----a表达式|b表达式 匹配a或者b表达式中的内容,如果匹配a成功了,不会继续和b匹配。 所以,如果两个规则有重叠部分,总是把长的放在前面
    () 约束

    例如:www\.(baidu|jd|taobao)\.com
    
    三、量词

    {n} 表示匹配n次
    {n,} 表示最少匹配n次
    {n,m} 表示最少匹配n次,最多匹配m次
    ? 匹配0次或1次 {0,1}
    * 匹配0次或n次 {0,}
    + 匹配1次或n次 {1,}

    四、贪婪匹配和惰性匹配

    ① 贪婪匹配:在量词允许的情况下,尽量匹配多个
    .x 表示匹配任意字符 任意多次数 遇到最后一个x才停下来
    ② 惰性匹配:在量词允许的情况下,尽量匹配少的内容,在量词后面加 ? 就是惰性匹配
    .
    ?x 表示匹配任意字符 任意多次数 但是一旦遇到x就停下来

    五、转义符

    ① 原本有特殊意义的字符,到了表达它本身的意义的时候,需要转义
    \.
    \*
    \?
    \(
    \)
    \+
    ② [().*+?] 所有的内容在字符组中会取消它的特殊意义
    ③ [a-c] -在字符组中表示范围,如果不希望它表示范围,需要转义,或者放在字符组的最前面或者最后面

    六、re模块
    1. re模块中最重要的两个方法是findall 和 search
      ① 基本用法:
    import re
    s = '19740ash93010uru'
    resp = re.findall("\d+", s)
    print(resp) # ['19740', '93010']
    
    resp1 = re.search("\d+", s)
    print(resp1)
    if resp1:
      print(resp1.group()) # '19740'
    

    由上面的例子可以看出:
    findall是根据正则表达式,匹配出所有符合的字段。
    search是根据正则表达式,找到第一个符合的字段,并且得通过group()方法获取字段的值
    ② 分组模式
    我们常说的分组就是按括号分组,出现一个括号即为分组
    例子:

    import re
    s = '19740ash93010uru'
    # 一个括号的情况
    resp = re.findall("9(\d)", s)
    print(resp) # ['7', '3']  优先显示括号匹配到的内容,以列表的形式返回
    #两个以上括号
    resp1 = re.findall("9(\d)(\d)(\d)", s)
    print(resp1) #[('7', '4', '0'), ('3', '0', '1')]   显示括号匹配到的内容
    
    # 按照完整的正则进行匹配,显示匹配到的第一个内容,但是我们可以通过给group方法传参数来获取具体文组中的内容
    resp2 = re.search("9(\d)(\d)(\d)", s)
    print(resp2) # <re.Match object; span=(1, 5), match='9740'>
    print(resp2.group()) # 9740
    print(resp2.group(1)) # "7"
    print(resp2.group(2)) # "4"
    print(resp2.group(3)) # "0"
    

    看了例子应该能明白,为啥要使用分组,分组就是为了获取真正想要的内容。

    如果实际工作中,遇到了不得已的情况加了括号,即用了分组的模式,为了不显示这个分组,可以用(?:),在分组的正则前加上?:就不会显示这个分组。

    ③ 分组命名
    有种情况,就是分组比较多的时候,用group(n)再去获取的时候很难点清是第几个分组。这时候可以给分组命名一个别名,通过group(name)的形式获取内容。
    (?P<分组名字>正则表达式)
    读取:ret.group('名字')
    例子:

    import re
    ret = re.search('\d(\d)\d(\w+?)(\d)(\w)\d(\d)\d(?P<name1>\w+?)(\d)(\w)\d(\d)\d(?P<name2>\w+?)(\d)(\w)','123abc45678agsf_123abc45678agsf123abc45678agsf')
    print(ret.group('name1'))
    print(ret.group('name2'))
    

    另外一种情况,在做爬虫的时候,比如要获取一个网页标签内的真正的内容,由于标签的特殊性,开头<abc>,结尾就是</abc>,字符串是一致的,这时候就可以使用分组命名,结尾处引用之前的名字即可。
    例子:

    import re
    exp= '<abc>akd7008&(&*)hgdwuih</abb>008&(&*)hgdwuih</abd>'
    ret= re.search('<(?P<tag>\w+)>.*?</(?P=tag)>',exp) # 通过?P=名字 的方式进行引用
    ret= re.search(r'<(\w+)>.*?</\1>',exp) #也可以通过\1方式来说明我是引用的第几个命名(\1需要转义,也可前面加r),这种方式不常用
    ret= re.search('<(\w+)>.*?</\\1>',exp) 
    print(ret)
    

    ④ 取消优先分组 (?:)
    在遇到不得不使用括号的时候,括号内的内容会被当做分组给展示出来,如果不想要这个括号内的内容可以用(?:正则)的方式取消这个分组的显示。

    ⑤ flags 参数

    re.I
        IGNORECASE
        忽略字母大小写
    
    re.L
        LOCALE
        影响 “w, “W, “b, 和 “B,这取决于当前的本地化设置。
    
    re.M
        MULTILINE
        使用本标志后,‘^’和‘$’匹配行首和行尾时,会增加换行符之前和之后的位置。
    
    re.S
        DOTALL
        使 “.” 特殊字符完全匹配任何字符,包括换行;没有这个标志, “.” 匹配除了换行符外的任何字符。
    
    re.X
        VERBOSE
        当该标志被指定时,在 RE 字符串中的空白符被忽略,除非该空白符在字符类中或在反斜杠之后。
        它也可以允许你将注释写入 RE,这些注释会被引擎忽略;
        注释用 “#”号 来标识,不过该符号不能在字符串或反斜杠之后。
    
    

    2.re 其他模块
    ① sub:替换, 可以通过参数控制替换几次,默认全部

    import re
    ret = re.sub('\d+', 'H', 'alex123wusir456', 1)
    print(ret) # alexHwusir456
    ret = re.sub('\d+', 'H', 'alex123wusir456', 2)
    print(ret) # alexHwusirH
    

    ② subn :元组的方式返回,会多返回替换的次数

    import re
    ret = re.subn('\d+', 'H', 'alex123wusir456')
    print(ret) # alexHwusirH
    

    ③ match: 会自动给正则加个 ^,主要是强调开头必须匹配
    ④ compile:可以节省代码的运行时间

    # 假如一个正则需要匹配多次,compile达到了只解析一次重复使用的作用
    ret = re.compile('\d+')
    res1 = ret.search('alex37176')
    res2 = ret.findall('alex37176')
    print(res1)
    print(res2)
    

    ⑤ finditer:节省代码空间,返回的是一个迭代器

    ret = re.finditer('\d+','agks1ak018093')
    for i in ret:
        print(i.group()) 
    # 1
    # 018093
    

    相关文章

      网友评论

          本文标题:19 正则表达式和re模块

          本文链接:https://www.haomeiwen.com/subject/oyulsktx.html