正则表达式:标志与替换

标志(flags)改变匹配器的行为,例如是否忽略大小写、是否跨行处理。替换则将找到的结果改写成新文本。本篇用 JavaScript 字面量 /模式/标志 直观展示常见字母,再在下一课映射到 Python 与 PowerShell API;不要把字面量语法直接复制进 Python。

标志不是完全通用

g 是 JavaScript 中“继续查找”的标志;Python 更常通过 findall、finditer 或 sub 这类 API 获取全部结果。i、m、s 在许多引擎中存在,但名称、内联写法与 Unicode 细节可能不同。PowerShell 的 -match 默认忽略大小写,若契约区分大小写应使用 -cmatch。

1. 全局匹配:g

功能说明

在 JavaScript 中,g 让匹配 API 或替换 API 继续查找后续结果,而不是只处理第一个命中。是否真正返回全部结果还与所调用的方法有关,例如 matchAll 和 replace 的行为不同于 test。

语法格式

/模式/g

简单示例

"id=12; id=34".match(/\d+/g)

匹配结果说明

结果为 ['12', '34']。移除 g 后,match(/\d+/) 通常只返回第一个数字 12 及其附加匹配信息。Python 中可用 re.findall(r'\d+', text) 获取同样的两个结果。

2. 忽略大小写:i

功能说明

i 让字母匹配时不区分大小写。它主要用于英文等大小写有差异的文字;Unicode 字母的大小写折叠规则比 ASCII 更复杂,跨语言数据需要使用目标引擎测试。

语法格式

/模式/i

简单示例

"Error ERROR error".match(/error/gi)

匹配结果说明

结果为 ['Error', 'ERROR', 'error']。g 负责找到所有结果,i 负责忽略字母大小写;没有 i 时,模式 error 只会匹配最后一个小写实例。

3. 多行模式:m

功能说明

m 改变 ^ 和 $ 的含义:它们除了匹配整个输入的开始与结束,也能匹配每一行的开始与结束。多行模式不会让点号 . 自动跨越换行,跨行匹配由单行(dotAll)模式控制。

语法格式

/^模式$/m

简单示例

"ok\nERROR: disk full\nok".match(/^ERROR:.*$/m)

匹配结果说明

结果是 ERROR: disk full。没有 m 时,^ 与 $ 只约束整个三行字符串,因此这条居中的错误行不会匹配。

4. 单行模式(dotAll):s

功能说明

s 常被称为单行模式或 dotAll 模式:它让点号 . 也能匹配换行符。名称中的“单行”容易误导,它不改变 ^ 和 $ 的行为;后者仍要使用 m。

语法格式

/开始.*结束/s

简单示例

"<p>第一行\n第二行</p>".match(/<p>.*<\/p>/s)

匹配结果说明

结果是整个 <p>第一行\n第二行</p> 片段。没有 s 时,点号无法越过换行,模式不匹配。对于 HTML、JSON 等有嵌套结构的文本,正则只能用于受控的小片段,不能代替真正的解析器。

5. 正则表达式替换

功能说明

替换操作先用正则找到目标,再用指定文本或函数生成新内容。它常用于规范空白、脱敏、批量修改格式。替换前应先检查匹配结果,并尽量在副本或测试数据上运行。

语法格式

文本.replace(/模式/g, "替换文本")

简单示例

"姓名   年龄\t城市".replace(/\s+/g, " ")

匹配结果说明

结果为 姓名 年龄 城市。\s+ 找到每一段连续空白,g 确保全部替换成一个普通空格。若移除 g,通常只会替换第一段连续空白。

6. 捕获组在替换中的使用

功能说明

替换文本可以引用捕获组,从而重排、保留或格式化已匹配的子内容。JavaScript 替换字符串中常用 $1、$2;Python 常用 \g<1>、\g<2>,不要混用两种语法。

语法格式

文本.replace(/(组1)(组2)/g, "$2$1")

简单示例

"日期:2026-07-12".replace(/(\d{4})-(\d{2})-(\d{2})/g, "$3/$2/$1")

匹配结果说明

结果为 日期:12/07/2026。正则先把年、月、日分别捕获为第 1、2、3 组,再按“日/月/年”的顺序写入替换文本。若使用命名捕获组,JavaScript 可通过 $<name> 引用,读起来通常更清晰。

7. 常用匹配模式的边界意识

功能说明

常用模式常用于初步结构筛选,例如整数、简易邮箱或版本号。但“看起来像”不等于“业务上有效”:邮箱可投递性、日期存在性、电话号码归属等都需要额外验证,不应只依赖正则。

语法格式

整数:^-?\d+$
简单版本号:^\d+\.\d+\.\d+$
简易邮箱结构:^[^\s@]+@[^\s@]+\.[^\s@]+$

简单示例

^\d+\.\d+\.\d+$

测试文本:1.2.3、v1.2.3、1.2、1.2.3.4

匹配结果说明

只有 1.2.3 匹配,因为它由恰好三段数字组成,并用句点分隔。它不判断版本号范围或语义;例如 999.999.999 在结构上仍会匹配。

练习与自测

  1. 解释 m 与 s 分别改变什么;为什么“多行”不等于“点号跨行”?
  2. 在 Python 中用 re.MULTILINE 找出所有以 ERROR: 开头的行,再用 finditer 输出行内位置。
  3. 分别写出 JavaScript、Python 和 PowerShell 的“把连续空白替换为一个空格”,标注替换引用语法差异。
  4. 用函数替换将每个数字加一;说明为什么复杂替换逻辑不应硬塞进替换字符串。
  5. 为简易版本号模式补充最大段长度,并说明结构校验与版本语义校验的边界。

上一节:先行与后行断言|下一节:Python re 与 PowerShell 实用 API。