【Python Cookbook】S02E08 编写多行模式的正则表达式

问题

我们打算使用正则表达式对一段文本做匹配,但是希望在进行匹配时能够跨越多行。换句话说,正则表达式中 . 可以匹配任意除了换行符的字符,我们如何让他也能够匹配换行符?

解决方案

例如在如下的两个案例中,text1 为单行内容,text2 内容分在了多行,pattern 为正则化匹配模式。

import re

pattern = re.compile(r'/\*(.*?)\*/')
text1 = "/* This is a commment */"
text2 = '''/* This is a
multiline comment.*/'''

print("text1 result:", pattern.findall(text1))
print("text2 result:", pattern.findall(text2))

结果:

text1 result: [' This is a commment ']
text2 result: []

关于正则化的匹配模式,在这里简述,若读者想要了解更清楚,可以移步博文:【Python Cookbook】S01E24 如何定义正则表达式模式从而准确匹配内容,通过 ? 调整贪心策略为非贪婪

在正则化匹配模式 '/\*(.*?)\*/'

  • /\*:这里有三个字符,分别是 / \ *,其目标是为了匹配字符串中的 /* 内容。而另外的一个字符,反斜杠 \,则是用于转义星号,使其成为普通字符。

  • (.*?):这是一个捕获组。

    • 最基础的圆括号 () 表示捕获匹配的内容
    • . 表示任意字符(除了换行符)
    • ? 表示非贪婪匹配模式,即尽可能少地匹配字符
    • * 表示前一个字符可以出现 0 次或多次。因此,这个捕获组会匹配尽可能少的任意字符,当然除了换行符。
  • \*/:与前面的 /* 类似,匹配字符串中的 */ 符号。同样,反斜杠用于转义星号,使其成为普通字符。

总而言之,上述正则表达式模式用于匹配被 /**/ 包裹的任意文本。但是,不包含换行符。

所以我们应该如何实现换行符也能够匹配呢?通过加入 \n

pattern = re.compile(r'/\*(.*?|.*?\n.*?)\*/')

优化上述模式匹配为:

pattern = re.compile(r'/\*((.|\n)*?)\*/')

正则化匹配模式 /\*((.|\n)*?)\*/ 解释:

前后的内容 /\* \*/ 上述已讲述,不过多赘述,\n 读者应当也熟识,为标准的换行符。

  • ((.|\n)*?) 模式中,各部分含义为:
    • . 还是表示任意除了换行符的字符
    • | 或者的含义,没有加转义字符就是原意
    • (.|\n) 的含义即,“不包含换行符” 或 “换行符”,即,包含换行符的任意字符
    • * 表示前一个字符可以出现 0 次或多次,在这里,(.|\n)* 即可以出现多次任意字符
    • ? 非贪婪模式,结合到整体模式中,即不贪婪的匹配所有在 /* */ 中的,包含换行符的任意字符。

再优化:

pattern = re.compile(r'/\*((?:.|\n)*?)\*/')

新增内容为 ?:,这是什么含义?

  • 在正则化匹配中,?: 是一个非捕获组的标记。其创建一个分组,但不同于普通捕获组,非捕获组不会保存匹配到的文本,也不会影响正则表达式引擎的回溯引用功能。

  • 区别于普通捕获组,其可以避免额外的存储开销,因为它告诉正则表达式引擎不要保存该分组的匹配结果。

讨论

上文我们花了大片篇幅来说明如何使得匹配时候包含换行符,但是其实,re.compile() 函数可接受一个有用的标记,re.DOTALL,这个标识使得正则表达式中的句点 . 可以匹配包含换行符在内的所有符号内容。

import re

pattern = re.compile(r'/\*(.*?)\*/', re.DOTALL)
text1 = "/* This is a commment */"
text2 = '''/* This is a
multiline comment.*/'''

print("text1 result:", pattern.findall(text1))
print("text2 result:", pattern.findall(text2))

结果:

text1 result: [' This is a commment ']
text2 result: [' This is a\nmultiline comment.']

综上所述,对于简单的情况,我们使用 re.DOTALL 标记就可以很好的完成工作。但是如果要处理及其复杂的情况,就需要我们自行定义正则化表达式模式了。

相关推荐

  1. 02_表达应用

    2024-06-14 06:40:03       34 阅读
  2. 3.01【python表达式以及re模块

    2024-06-14 06:40:03       39 阅读
  3. week03day04(表达式2)

    2024-06-14 06:40:03       26 阅读
  4. Python 表达式:深入解析匹配模式

    2024-06-14 06:40:03       7 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-06-14 06:40:03       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-06-14 06:40:03       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-06-14 06:40:03       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-06-14 06:40:03       18 阅读

热门阅读

  1. msf原生shellcode迁移进程后如何获取攻击者ip

    2024-06-14 06:40:03       8 阅读
  2. Redis

    Redis

    2024-06-14 06:40:03      8 阅读
  3. 通过apex启动flow

    2024-06-14 06:40:03       9 阅读
  4. 鸿蒙开发电话服务:【@ohos.contact (联系人)】

    2024-06-14 06:40:03       8 阅读
  5. pg和oracle的区别

    2024-06-14 06:40:03       7 阅读
  6. 常见NI板卡

    2024-06-14 06:40:03       9 阅读
  7. 数据库select语句基础

    2024-06-14 06:40:03       7 阅读