Python 的 re 模块内置函数几乎都有一个 flags 参数,规定了正则匹配时的各种策略模式,其中有两个模式:单行(re.DOTALL, 或者re.S)和多行(re.MULTILINE, 或者re.M)模式。本文简单介绍下这两种模式的用法和使用场合。

目录

TL;DR

太长不看版:

单行模式和多行模式,都增强了对多行文本的解析能力。

单行模式突破换行符 \n 的阻碍,将匹配视野扩大到整个字符串

多行模式实现换行符 \n 的分隔,将匹配视野缩小到一行之内,并且按行分别匹配。

文件的保存形式:字节流

首先我们需要清楚,你看到的多行文本在视觉上是二维的,有行和列的表达:比如我们新建一个文件,名字叫 a.txt ,内容是:

cat

dog

用文本编辑器打开,看到的是两行文字,每行有三个字符,所以这是个二维的表示。

但是,文件的保存形式只能是一维的字节流,之所以能让编辑器表示为二维形状,都是因为字节流中包含了换行符。

我们用 xxd 命令看下这个 a.txt 文件的二进制表达:

$ xxd -b a.txt

0000000: 01100011 01100001 01110100 00001010 01100100 01101111 cat.do

0000006: 01100111 00001010 g.

这就是文件 a.txt 真实保存的形式,其中 00001010 就是换行符。

为了能看得更清楚,用16进制查看文件:

$ xxd a

0000000: 6361 740a 646f 670a cat.dog.

Linux环境下, 0a 就是换行符,在编程语言里用 '\n' 表示,不同操作系统下的换行符有少许不同,见这篇文章Python 换行符和多行模式

结论:一段多行文本,尽管在文本编辑器中显示为二维的形状,但是在正则表达式解析器看来,文件是一维的字符串。在碰到包含换行符的字符串时,有多种匹配模式,分别能得到不同的结果。

在线测试工具

首先我们使用一款在线工具以得到感性认识。(建议在 PC 端 Chrome 浏览器中使用,其他浏览器效果不能保证)。

复制下面一段多行文字:

空山新雨后,

天气晚来秋。

明月松间照,

清泉石上流。

并粘贴到下方文本框中:

在普通匹配模式 ".+" 下,得到如下的结果,匹配到第一行末尾即停止。

空山新雨后,

单行匹配模式 ".+", re.DOTALL 下,得到如下结果,可见匹配出了包括换行符在内的所有字符

空山新雨后,\n天气晚来秋。\n明月松间照,\n清泉石上流。

在多行匹配模式 "^.+$" re.MULTILINE 下,得到如下结果,可见匹配结果本身也是多行:

空山新雨后,

天气晚来秋。

明月松间照,

清泉石上流。

普通模式

正则表达式( Python2 , Python3 )里, 点号(.)能匹配除换行符以外的所有字符。

In the default mode, this matches any character except a newline.

当用 .* 匹配到换行符的前面时,匹配即停止。例如下面这样的字符串:

This is the first line.

This is the second line.

This is the third line.

直接使用 .* 匹配,匹配过程如下面图所示(点击右上角的“点击播放”):

执行代码的例子,如下面的执行过程。从匹配结果可以看出来,仅有第一行出现在结果里,而且不包含换行符。

> a = 'This is the first line.\nThis is the second line.\nThis is the third line.'

> print a

This is the first line.

This is the second line.

This is the third line.

> import re

> p = re.match(r'This.*line\.' ,a)

> p.group(0)

'This is the first line.'

>

结论:

普通模式下,点号(.)不能匹配换行符,匹配动作遇到换行符即停止。

单行模式 re.DOTALL

在上面的例子里,即使是默认的贪婪(greedy)模式,仍然在第一行的结尾初停止了匹配。如果想完整匹配出字符串,就需要进入 单行模式 。 Python 文档中这么描述:

If the DOTALL flag has been specified, this matches any character including a newline.

在单行模式下,匹配的行为模式如下图,点击右上角的“点击播放”查看匹配过程:

从上面的动图里可以看出,当使用 re.DOTALL 时,点号将同时匹配换行符,实现了跨行匹配。代码的执行过程如下,从下面的记过可以看出,匹配结果里包含了换行符 \n 和 全部的三行。

> q = re.match(r'This.*line\.', a, flags=re.DOTALL)

> q.group(0)

'This is the first line.\nThis is the second line.\nThis is the third line.'

结论:

单行模式下,点号(.)也能匹配换行符,多行文本被当作一行匹配。

这里引申出比较奇怪的结论就是:为了能匹配出多行文本,你应该使用单行模式。

多行模式 re.MULTILINE

有时候我们想找出一篇文章里符合特定条件一共有几行。比如在下面的例子里,我们希望找出 所有 以 This 开头,以 line 结尾的行。

> a = 'This is the first line.\nThis is the second line.\nThis is the third line.'

> print a

This is the first line.

This is the second line.

This is the third line.

> import re

> re.findall(r'^This.*line\.$', a)

[]

>

匹配结果为空的原因是:从 上一节 我们知道,点号不匹配换行符,最多只能匹配到第一个 line,但是第一个 line 后面并没有行尾符 $,假如我们改用 单行模式

> re.findall(r'^This.*line\.$', a, flags=re.DOTALL)

['This is the first line.\nThis is the second line.\nThis is the third line.']

>

匹配模式中的 line 就匹配到了第三个line,结果就是匹配出了整个字符串,但这并不是我们想要的, 因为原字符串的三行都满足匹配条件,我们希望有三条结果。

再用问号 ? 切换成非贪婪模式试试:

> re.findall(r'^This.*?line\.$', a, flags=re.DOTALL)

['This is the first line.\nThis is the second line.\nThis is the third line.']

>

仍然是整个字符串

真正的原因是因为正常情况下,行首符 ^ 和行尾符 $ 仅仅匹配整个字符串的起始和结尾。Python 文档中这么描述:

By default, ‘^’ matches only at the beginning of the string, and ‘$’ only at the end of the string and immediately before the newline (if any) at the end of the string.

为了扩大 ^ 和 $ 的匹配范围,引入了多行模式。在这种模式下:

将换行符 '\n' 后面的位置也看作行首,可以用 ^ 匹配

将换行符 '\n' 前面的位置也看作行尾,可以用 $ 匹配

点击下图右上角的“点击播放”,观看多行模式的匹配过程:

Python 文档中这么描述:

When specified, the pattern character ‘^’ matches at the beginning of the string and at the beginning of each line (immediately following each newline); and the pattern character ‘$’ matches at the end of the string and at the end of each line (immediately preceding each newline).

再回到前面的例子中,使用多行模式得到的结果如下:

> re.findall(r'^This.*line\.$', a, flags=re.MULTILINE)

['This is the first line.', 'This is the second line.', 'This is the third line.']

结论:

多行模式改变了^和 $ 符号的匹配策略,当字符串中间有 换行符 \n 时,将字符串当作独立的多行对待

当需要在一个文本文件里跨行匹配时,单行和多行模式尤其有用。

二者不冲突

单行模式和多行模式,从名字上看是互斥的,但是实际上,两者可以共存。因为它们二者分别扩展不同的匹配符:点号 . 和 ^、 $

python多行字符串变单行_Python 正则表达式里的单行s和多行m模式相关推荐

  1. Python 正则表达式里的单行s和多行m模式

    Python 的 re 模块内置函数几乎都有一个 flags参数,规定了正则匹配时的各种策略模式,其中有两个模式:单行(re.DOTALL, 或者re.S)和多行(re.MULTILINE,或者re. ...

  2. python中怎样使用re模块_PYTHON正则表达式 re模块使用说明

    首先,运行 Python 解释器,导入 re 模块并编译一个 RE: #!python Python 2.2.2 (#1, Feb 10 2003, 12:57:01) >>> im ...

  3. python怎样输出字符串和数字_Python 字符串与数字输出方法

    Python 字符串与数字输出方法 如下所示: x = 3 print(x+"nihao") 这样会报错 x = 3 print(x,"nihao") 这样不会 ...

  4. python中替换字符串中字符_python替换字符串中的某个字符

    python_split_strip_replace使用方法 使用python时会经常要对字符串做一些处理,比如:分割字符串.去掉空格.替换字符串 中的某个字符等,下面介绍下这几个功能的使用. 一.  ...

  5. python内置字符串处理函数_Python内置的字符串处理函数

    生成字符串变量 str='python String function' 字符串长度获取:len(str) 例:print '%s length=%d' % (str,len(str)) 连接字符串 ...

  6. pandas 把某一列中字符串变数值_Python学习教程:Python数据分析实战基础 | 初识Pandas...

    这段时间和一些做数据分析的同学闲聊,我发现数据分析技能入门阶段存在一个普遍性的问题,很多凭着兴趣入坑的同学,都能够很快熟悉Python基础语法,好像自己什么都会了一点,然而实际操作起来既不知从何操起, ...

  7. python如何正则匹配浮点值_Python正则表达式字符串数组到浮点数组

    我是python正则表达式的初学者.我达到了我所需要的,但是由于缺少经验,这真的很丑.我的目标是转换以下形式的字符串数组: notes = ["10.0% higher", &qu ...

  8. python正则匹配11个数字_Python正则表达式匹配字符串中的数字

    导读 这篇文章主要介绍了Python正则表达式匹配字符串中的数字,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下 1.使用"\d+"匹配全数字 ...

  9. python正则表达式提取字符串的字母_Python正则表达式提取一部分字符串

    1要提取大量烧成的一部分.有一个目标词和之前和之后单词的数量上限.因此所提取的子必须包含单词之前和之后它的上界目标字一起.在之前和之后的部分可以包含少言,如果目标字更接近文本的开头或结尾. 进行了串 ...

最新文章

  1. git 下载的文件与git上面的文件不相同的处理方法
  2. php比较运算符案列,PHP实例:PHP比较运算符的详细介绍
  3. nil 与 release
  4. UICamera(NGUI Event system)原理
  5. 诗与远方:无题(十七)
  6. C# Zip解压缩,规避 [content_types].xml 文件
  7. 智能家居火了这么久 何时到我家?
  8. 计算机网络章末总结,计算机网络 (前两章总结)
  9. 编程:从前有一个傻呆程序员,老婆交给他一项任务,他办了四次才满意
  10. pymysql封装总结
  11. 学科网软件测试,对比学科网和菁优网:选择二一组卷平台的N个理由
  12. python 分割线_用Python打印分割线练习
  13. Linux常用英文单词
  14. 《深入浅出图神经网络》
  15. oracle+suspend+参数,oracle数据库的挂起(Suspending)和恢复(Resuming)
  16. ios和android下数字没有垂直居中,手机端设置小号字体的上下居中问题
  17. Ubuntu设置扁平化风格桌面
  18. 运维人最重要的工具软件 -- VI
  19. 优秀互联网面试题总结
  20. Java斗_Java集合练习:斗地主游戏

热门文章

  1. java的actionlistener_「actionlistener」Java——事件处理机制监听者基础(一)动作监听ActionListener - seo实验室...
  2. openwrt取消strip 软件包
  3. 计算机防火墙打不开0x6d9,Win7系统打开防火墙出错显示0x6D9怎么处理
  4. 【VUE实战问题记录】只能输入自然数,包括0及两位小数
  5. 哈哈机器人送到冰雪小镇_约克VRF助力森林冰雪小镇,打造童话梦境
  6. 几种获取本机IPv6地址的方法
  7. 番茄花园Windows7 32位64位 旗舰装机版 v2022【全驱动】
  8. 2017-07-31关于敏捷开发的一些想法
  9. 由浅到深玩转Python爬虫(一)初识爬虫
  10. 高速版双底形态选股关联自选股票池!股票量化分析工具QTYX-V2.3.4