多行模式改的是什么
多行模式只改变起始与结束锚点的判定位置:从整段文本的首尾变成每一行的首尾。它不会让点号匹配换行,也不会改变量词的贪婪策略。很多人把多行模式与单行模式混为一谈,两者管的其实是完全不同的东西。
行的定义
行的边界就是换行符。不同系统的换行风格不一样,文本混用时锚点的落点也跟着变,处理跨平台文本前先确认换行是哪种形式,必要时统一换行风格再匹配。
基本信息
| 作用对象 | 仅影响起始与结束锚点的判定 |
|---|---|
| 不改动的部分 | 点号的换行行为、量词的贪婪策略、字符类内容 |
| Python 写法 | re.MULTILINE 或内联修饰符 (?m) |
| JavaScript 写法 | 模式后加 m 标志 |
| Java 与 .NET | Pattern.MULTILINE、RegexOptions.Multiline |
| 命令行工具 | grep、sed、awk 天然逐行处理,行为上接近多行模式 |
典型使用场景
- 从文本里逐行挑出符合格式的行,例如以某关键字开头的记录
- 统计空行、注释行、特定结尾的行数量
- 批量修改每一行的行首或行尾,例如统一加前缀或去掉尾巴空白
- 解析配置文件时按行定位键值对,避免跨行贪吃
- 校验多行输入中每一行是否都不含禁用字符
多行与单行模式对比
多行与单行模式对比
import re
t = 'a1\nb2\nc3'
re.findall(r'^\w\d', t) # 未开多行:只可能命中开头那一个
re.findall(r'^\w\d', t, re.M) # 开多行:每一行都尝试
re.findall(r'\d$', t, re.M) # 行尾锚点在多行模式下逐行生效
re.findall(r'^.*$', t, re.M) # 逐行取内容,注意点号仍不跨行
re.findall(r'^.*$', t, re.M | re.S) # 两个模式同时开:锚点逐行且点号跨行
re.sub(r'^', '# ', t, flags=re.M) # 在每行行首统一加标记模式开关职责划分
| 开关 | 改变了什么 | 没有改变什么 |
|---|---|---|
| 多行模式 | 锚点逐行生效 | 点号仍不匹配换行 |
| 单行模式 | 点号匹配换行 | 锚点仍只对整段首尾生效 |
| 忽略大小写 | 字符比较不区分大小写 | 字符类与量词语义不变 |
| 两开关同开 | 锚点逐行且点号跨行 | 量词贪婪策略仍不改 |
多行模式与单行模式可以同时开启且互不冲突。名字容易误导:多行管锚点,单行管点号。写多行文本处理时,先想清楚需要哪一个,再决定加哪个开关。
行尾锚点在有末尾换行的文本上会出现位置分歧:部分引擎允许它匹配末尾换行前的位置。逐行提取后如发现最后一行结果异常,先检查原文是否以换行结尾。