正则表达式(Regular Expression)是描述"字符串模式"的一套微型语言,验证表单、搜索替换、日志分析背后都离不开它。语法看起来像一堆乱码符号,但拆开来看,核心元字符和规则并不多。
正则表达式用一些特殊符号代表"一类字符"而不是某个具体字符:
| 元字符 | 含义 |
|---|---|
. |
匹配除换行符外的任意一个字符 |
\d |
匹配一个数字,等价于 [0-9] |
\w |
匹配一个字母/数字/下划线,等价于 [A-Za-z0-9_] |
\s |
匹配一个空白字符(空格、Tab、换行) |
^ |
匹配字符串开头 |
$ |
匹配字符串结尾 |
[abc] |
匹配方括号里任意一个字符(a 或 b 或 c) |
[^abc] |
匹配不在方括号里的任意一个字符 |
比如 ^\d{3}-\d{4}$ 能匹配"三位数字-四位数字"这种格式的字符串(\d{3} 的含义见下一节的量词)。
量词跟在一个字符或分组后面,控制它能重复出现几次:
| 量词 | 含义 |
|---|---|
* |
出现 0 次或多次 |
+ |
出现 1 次或多次 |
? |
出现 0 次或 1 次(可选) |
{n} |
恰好出现 n 次 |
{n,} |
出现至少 n 次 |
{n,m} |
出现 n 到 m 次 |
比如手机号简化匹配 1\d{10} 表示"1 开头,后面跟 10 个数字"(共 11 位);colou?r 能同时匹配英式 colour 和美式 color,因为 u? 表示 u 出现 0 次或 1 次。
需要注意贪婪与非贪婪的区别:*、+、{n,m} 默认是"贪婪"的,会尽可能多地匹配字符;在后面加一个 ? 变成非贪婪(比如 *?),会尽可能少地匹配。处理 HTML 标签这类有嵌套结构的文本时,贪婪模式经常会匹配过多内容,这是新手常踩的坑。
用圆括号 () 包裹的部分叫"捕获组",除了整体匹配结果,还能单独取出括号里匹配到的内容。比如用 (\d{4})-(\d{2})-(\d{2}) 去匹配日期字符串 2025-03-15,整体匹配是 2025-03-15,同时能分别取出第一个捕获组 2025、第二个 03、第三个 15——这在提取结构化信息、做字符串替换(比如把日期格式从 2025-03-15 转成 15/03/2025)时非常有用。
还可以给捕获组命名(比如 (?<year>\d{4})),用名字而不是数字下标引用,可读性更好;如果只想分组但不需要单独取出结果,可以用 (?:...) 非捕获组,减少不必要的开销。
正则表达式后面常跟一个或多个修饰符(Flag),控制整体的匹配行为:
g(global):查找所有匹配,不是只找到第一个就停止i(ignore case):忽略大小写m(multiline):让 ^ 和 $ 匹配每一行的开头结尾,而不只是整个字符串的开头结尾s(dotAll):让 . 也能匹配换行符(默认不匹配)正则表达式在不同编程语言之间语法大体相通,但转义规则、修饰符写法有细节差异(比如 Python 需要在字符串前加 r 避免反斜杠被转义两次),跨语言迁移正则时需要留意这些差异。