• 正则表达式


    一、语法

    正则表达式的语法是独立于编程语言的。

    1. 位置字符
    • ^: 匹配字符串开始位置
    • $: 匹配字符串结束位置
    • |: 中|美国匹配"中""美国"(中|美)国匹配"中国""美国"
    • A: 只匹配字符串的开始位置
    • : 只匹配字符串的结尾
    • 
    • B
    2. 元字符
    • : 隐藏特殊字符的特殊含义。Python中"\"打印出来就是r"\"打印出来就是\,所以要匹配""字符串,正则表达式应该为\\
    • .: 匹配除换行符以外的任何字符,如果指定了DOTALL,那么匹配所有字符。
    • d: [0-9]
    • D: [^0-9]
    • s: [ fv]
    • S: [^ fv]
    • w: [a-zA-Z0-9_]
    • W: [^a-zA-Z0-9_]
    3. 集合[]
    • 集合: [abc]匹配"a""b""c"
    • 范围集合: [a-z], [0-9], [A-Z]
    • 特殊字符()+*在集合中会失去特殊含义,W等字符类在集合中不会失去含义。
    • 集合的反义: ^,集中中匹配"^"需要使用[^^]
    4. 数量词
    • *: 任意次数
    • +: 大于等于1
    • ?: 0或者1
    • *?, +?, ??: *+?都是贪婪模式,它们会匹配尽可能长的文本,比如<.*>可以匹配<a>b<c>整个字符串,给他们加上?会调整至最小模式。
    • {m}: 匹配指定次数
    • {m,n}, {m,n}?: 前者是贪婪模式,后者是最小模式
    5. 捕获组
    • (...): 捕获组,一旦匹配组中的内容便可抽取得到,并在后面通过 umber来匹配;如果直接匹配括号,比如(需要([(]
    • (?...): 这是一个扩展符号,?后面的第一个字符决定具体的含义到底是什么,这个扩展一般不会创建一个组,唯一的特例是(?P<name>...)
    • (?aiLmsux): 这个组不匹配字符串,它是对整个字符串的flag设置,这种方法和直接把flag当做参数传递给re.compile()的区别是,它把flag设置放在了正则表达式里面。设置的时候,选择一个或者多个字母,含义依次等同re.A(ASCII-only matching),re.I(忽视大小写),re.L(locale dependent),re.M(多行),re.S(.匹配所有字符),re.U(Unicode匹配),re.X(verbose)

    • (?:...): 非捕获组,其中的内容不会被抽取出来
    • (?P<name>...): 命名捕获组
    • (?P=name): 引用前面的命名捕获组,但是二者的内容必须一样
    • (?#...): 注释文字
    • (?=...)(?!...): 匹配在(不在)指定模式文本前面的字符串
    • (?<=...)(?<!...): 匹配在(不在)指定模式文本后面的字符串
    • (?(id/name)yes-pattern|no-pattern)

    二、python中常用的api

    1. 搜索查找
    re.search(pattern, string, flags=0)
    re.findall(pattern, string, flags=0)  # 返回列表
    re.finditer(pattern, string, flags=0)  # 返回迭代器
    
    2. 匹配校验
    re.match()  # 开头匹配
    re.fullmatch()  # 完全匹配
    
    3. 替换
    re.sub(pattern, repl, string, count=0, flags=0)
    re.subn(pattern, repl, string, count=0, flags=0)
    
    4. 拆分
    re.split(pattern, string, maxsplit=0, flags=0)
    

    三、示例

    在python中,r会取消字符串中的转义效果

    print('r和不加r的区别:')
    print(r'
    ')
    print('
    ')  # 打印出两个换行
    print('='*50)
    res = re.match(r'd+', '3333')
    print(res)
    res = re.match('\d+', '3333')  # \会变成一个,丢给re
    print(res)
    print('='*50)
    

    运行结果:

    r和不加r的区别:
    
    
    
    
    ==================================================
    <re.Match object; span=(0, 4), match='3333'>
    <re.Match object; span=(0, 4), match='3333'>
    ==================================================
    

    捕获组

    • group()直接返回的是整个正则字符串匹配的内容,也是0号捕获组;
    • group()接受序号名字作为参数,它返回的就是对应捕获组的内容;
    • groups()以元组的形式返回所有捕获组的内容;
    res = re.match(r'(欧文|杜兰特)打败了(哈登|杜兰特)', '欧文打败了杜兰特')
    print(res)
    print('group():', res.group(), ', start():', res.start(), ', end():', res.end(), ', span():', res.span())
    print('group(1):', res.group(1), ', start(1):', res.start(1), ', end(1):', res.end(1), ', span(1):', res.span(1))
    print('group(2):', res.group(2), ', start(2):', res.start(2), ', end(2):', res.end(2), ', span(2):', res.span(2))
    print('groups():', res.groups())
    print('='*50)
    

    运行结果:

    <re.Match object; span=(0, 8), match='欧文打败了杜兰特'>
    group(): 欧文打败了杜兰特 , start(): 0 , end(): 8 , span(): (0, 8)
    group(1): 欧文 , start(1): 0 , end(1): 2 , span(1): (0, 2)
    group(2): 杜兰特 , start(2): 5 , end(2): 8 , span(2): (5, 8)
    groups(): ('欧文', '杜兰特')
    ==================================================
    

    接下来看命名捕获组的示例

    print('模式中根据名称重复使用一个模式:')
    res = re.search(r'(?P<player>欧文|杜兰特)打败了(?P=player)', '欧文打败了欧文')  # 字符串必须一模一样
    print("方法一:", res)
    res = re.search(r'(?P<player>欧文|杜兰特)打败了1', '欧文打败了欧文')  # 字符串必须一模一样
    print("方法二:", res)
    
    print('在替换的时候引用命名捕获组')
    res = re.sub(r'(?P<winner>欧文|杜兰特)打败了(?P<loser>欧文|杜兰特)', 'winner is g<winner>, loser is g<loser>', '欧文打败了杜兰特')
    print('方法一:', res)
    res = re.sub(r'(?P<winner>欧文|杜兰特)打败了(?P<loser>欧文|杜兰特)', 'winner is g<1>, loser is g<2>', '欧文打败了杜兰特')
    print('方法二:', res)
    res = re.sub(r'(?P<winner>欧文|杜兰特)打败了(?P<loser>欧文|杜兰特)', 'winner is \1, loser is \2', '欧文打败了杜兰特')
    print('方法三:', res)
    

    运行结果

    模式中根据名称重复使用一个模式:
    方法一: <re.Match object; span=(0, 7), match='欧文打败了欧文'>
    方法二: <re.Match object; span=(0, 7), match='欧文打败了欧文'>
    在替换的时候引用命名捕获组
    方法一: winner is 欧文, loser is 杜兰特
    方法二: winner is 欧文, loser is 杜兰特
    方法三: winner is 欧文, loser is 杜兰特
    

    接下来是前向后向查看。

    # lookahead assertion
    texts = ['15岁', '15周岁', '15年']
    for text in texts:
        res = re.search(r'd+(?=周?岁)', text)
        print(res.string if res else res)
    
    print('='*50)
    
    # negative lookahead assertion
    texts = ['检测肝瘤为阳性', '检测脑瘤为阴性']
    for text in texts:
        res = re.search(r'检测(.+瘤)为(?!阴性)', text)
        print(res.string if res else res)
    

    运行结果

    15岁
    15周岁
    None
    ==================================================
    检测肝瘤为阳性
    None
    

    以及

    texts = ['@qq.com', '@163.com', 'google.com']
    for text in texts:
        res = re.search(r'(?<=@)[a-zA-Z0-9]+', text)
        print(res.string if res else res)
    
    print('='*50)
    

    结果

    @qq.com
    @163.com
    None
    
  • 相关阅读:
    数据结构之查找算法总结笔记
    html的a链接的href怎样才另起一个页面
    深入理解CSS中的空白符和换行
    CSS文本方向
    alert()与console.log()的区别
    CSS旧版flex及兼容
    Java:类与继承
    Java中只有按值传递,没有按引用传递!
    String作为方法参数传递 与 引用传递
    Java:按值传递还是按引用传递详细解说
  • 原文地址:https://www.cnblogs.com/YoungF/p/14437775.html
Copyright © 2020-2023  润新知