• 详解正则表达式(re) 一


    详解正则表达式(re) 一

    re

    正则表达式 可以用形式化的语法描述文本匹配模式,模式又被正则表达式引擎编译成指令;执行指令并提供一个字符串作为输入,就可以知道给定的输入有没有与模式相匹配。 文字比较空洞还是直接看例子吧。

    re


    查找一段文本中有没有出现 sql 这个字符串。

    In [1]: s ="I like sql"                                                         
    
    In [2]: 'sql' in s                                                              
    Out[2]: True
    

    可以看到根本没有用到 re 这个库就把问题给解决了;但是没有 bug 吗?

    In [3]: s = "I like www.sqlpy.com"                                              
    
    In [4]: 'sql' in s                                                              
    Out[4]: True
    # 这样的太不应该了,我想要的只是 sql 而不是 xxxsqlxx。
    

    用 re 就没有 bug 了。

    In [1]: import re                                                               
    
    In [2]: p = r"sql"                                                          
    
    In [3]: s = "I like sql"                                                        
    
    In [4]: re.search(p,s)                                                          
    Out[4]: <re.Match object; span=(7, 10), match='sql'>
    
    In [5]: s = "I like www.sqlpy.com"                                              
    
    In [6]: re.search(p,s)           # 可以看到不在有匹配                                               
    
    In [7]:
    

    原因在于用 re 我们把可以把自己要找到内容描述的更加清楚,'sql' in s 讲的是 s 中是否包含sql 这三个字符,而 r"sql" 描述的是 'sql' 这个单词。


    compile 编译

    上面的代码还有一个问题,re.search(p,s) 运行到这里的时候就会对模式进行编译,运行几次就编译几次,对于反复用到的模式提前编译是一个好的选择。下面是两种处理方式的性能比较。

    #!/usr/bin/evn python3
    
    import re
    import time
    
    # 提前把用到的模式编译好
    global_pattern = re.compile(r"sql")
    
    
    def fun_a():
        """在每次用的时候都编译模式
        """
        p = r"sql"
        s = "I like sql"
        return re.search(p, s)
    
    
    def fun_b():
        """使用提交编译好的模式
        """
        global global_pattern
        s = "I like sql"
        return global_pattern.search(s)
    
    
    def run(fun, times=1000):
        start_at = time.time()
        for t in range(times):
            fun()
    
        complete_at = time.time()
        print(
            f"function {fun.__name__} execute {times} times cost {complete_at - start_at}")
    
    
    if __name__ == "__main__":
        run(fun_a, 10000)
        run(fun_b, 10000)
    

    运行结果。

    python3 main.py 
    function fun_a execute 10000 times cost 0.013822078704833984
    function fun_b execute 10000 times cost 0.006231784820556641
    

    可以看到提前编译要比即时编译快 100% 。


    findall 查询所有匹配

    通过 search 只能知道有没有匹配,如果有多处匹配我们怎么提取出来呢?

    In [1]: import re                                                               
    
    In [2]: s = "ab abb abbb abbbb"                                                 
    
    In [3]: p = r"ab*"                                                              
    
    In [4]: re.search(p,s)                                                          
    Out[4]: <re.Match object; span=(0, 2), match='ab'>
    
    In [5]: for m in re.findall(p,s): 
       ...:     print(m) 
       ...:                                                                         
    ab
    abb
    abbb
    abbbb
    
    In [6]: type(re.findall(p,s))                                                   
    Out[6]: list
    

    可以看到 findall 返回的是一列表而列表的元素是字符串,如果有大量的结果被匹配到,比如几千几亿个,这个 list 是非常吃内存的,理节约内存的方式是使用生成器。

    In [7]: for m in re.finditer(p,s): 
       ...:     print(m) 
       ...:                                                                         
    <re.Match object; span=(0, 2), match='ab'>
    <re.Match object; span=(3, 6), match='abb'>
    <re.Match object; span=(7, 11), match='abbb'>
    <re.Match object; span=(12, 17), match='abbbb'>
    
    
    In [8]: type(re.finditer(p,s))                                                  
    Out[8]: callable_iterator
    

    重复与贪婪

    正则表达式对重复的描述包含 5 种形式。

    1、ab* 说的是 'a' 后面的 'b' 可以是零个也可以是任意多个。 2、ab+ 说的是 'a' 后面的 'b' 至少是一个。 3、ab? 说的是 'a' 后面的 'b' 要么没有要么只有一个。4、ab{5}说的是 'a' 后面的 'b' 一定要是 5 个,当然这里的 5 也可以改在其它的数值,视需求而定。 5、ab{5,8} 说的是可以是 5 个到 8 个之间([5,8]开边都是闭区间)。

    默认情况下正则表达式工作在贪婪模式,也就是说它会倾向于匹配出更多的字符串,看一下面的例子。

    In [1]: import re                                                               
    
    In [2]: s = "abbbb"                                                             
    
    In [3]: p = "ab*"                                                               
    
    In [4]: re.search(p,s)                                                          
    Out[4]: <re.Match object; span=(0, 5), match='abbbb'>
    

    怎么让它匹配出尽可能少的字符串呢?答案是在正则表达式的结尾处加上一个?号,看下面的代码。

    In [5]: p = "ab*?"                                                              
    
    In [6]: re.search(p,s)                                                          
    Out[6]: <re.Match object; span=(0, 1), match='a'>
    
  • 相关阅读:
    装备购买 线性基+贪心
    花园 状压DP+矩阵快速幂
    数学作业 递推+矩阵快速幂
    石头游戏 构造+矩阵快速幂
    sumdiv 算术基本定理的推论
    huffman
    Integer 类型比较大小
    java 中的 String 相加
    Java 中的 static 关键字
    JAVA 基础
  • 原文地址:https://www.cnblogs.com/JiangLe/p/12687155.html
Copyright © 2020-2023  润新知