跳转到主要内容
返回文章列表

正则表达式基础

Others3 分钟阅读 · 977
#Others#正则表达式#文本处理#字符串匹配

问题

正则表达式是什么?常见语法有哪些?写正则时最容易踩哪些坑?

回答

核心结论

正则表达式可以理解为一套“文本匹配规则”,常用于:

  • 校验输入格式
  • 提取文本中的目标片段
  • 批量替换内容
  • 在日志、配置、代码中做模式搜索

它的优势是表达紧凑,缺点是可读性容易快速下降,所以实际使用中要坚持两个原则:

  • 能写清楚就不要写太花
  • 能做粗校验就不要假装做强校验

基础语法速查

符号 含义 示例
. 默认匹配除换行外的任意单个字符 a.c 可匹配 abca1c
* 前一个模式重复 0 次或多次 ab*c 可匹配 acabbc
+ 前一个模式重复 1 次或多次 ab+c 可匹配 abcabbbc
? 前一个模式重复 0 次或 1 次 colou?r 可匹配 colorcolour
^ 字符串开头 ^hello
$ 字符串结尾 world$
` `

字符类与常用简写

写法 含义
[abc] 匹配 abc 中任意一个
[a-z] 匹配任意小写字母
[^0-9] 匹配任意非数字字符
\d 数字
\w 字母、数字、下划线
\s 空白字符
\D 非数字
\W 非字母数字下划线
\S 非空白字符

量词

量词 含义
{n} 恰好 n 次
{n,m} n 到 m 次
{n,} 至少 n 次
*? 懒惰匹配
+? 懒惰匹配

分组与捕获

(ab)+

含义:把 ab 当作一个整体,整体重复一次或多次。

常见分组有两类:

  • (...):捕获组,后续可以读取匹配结果
  • (?:...):非捕获组,只分组,不关心保存结果

捕获示例(Python)

import re

text = "电话:138-1234-5678"
pattern = r"(\d{3})-(\d{4})-(\d{4})"
match = re.search(pattern, text)

print(match.group(1))
print(match.group(2))
print(match.group(3))

输出依次是:

  • 138
  • 1234
  • 5678

贪婪与懒惰

<.*>

默认是贪婪匹配,会尽可能多吃字符。

例如在 <b>hi</b> 上,<.*> 可能一次吞掉整个字符串。

如果你只想匹配最短的一段,通常改成:

<.*?>

这就是懒惰匹配

常见示例

1. 纯数字

^[0-9]+$

表示整段字符串只能由数字组成。

2. 提取文件扩展名

\.([a-zA-Z0-9]+)$

3. 粗略校验邮箱

^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$

这个表达式适合前端表单或简单文本过滤,但不适合当作严格的邮箱合法性校验规则,因为真实邮箱规则远比它复杂。

最容易踩的坑

坑点 说明
误以为 . 真的是“任意字符” 很多引擎默认不匹配换行
忘记转义 想匹配点号时应该写 \.
贪婪匹配过头 .* 很容易吃掉比预期更多的内容
把正则当万能解析器 HTML、SQL、复杂语法树通常不适合只靠正则解析
忽略语言差异 Java、Python、JavaScript 在转义和特性支持上存在差异

一句话总结

正则表达式本质上是“文本匹配规则”,适合做搜索、提取和粗校验;写得越短不一定越好,写得越清楚才越实用。

相关问题

  • ^$ 有什么用? → 用来限制匹配范围,避免只命中字符串的一部分。
  • 为什么有时候一个正则在 Python 能用,在 JavaScript 里不一样? → 因为不同语言的正则引擎和字符串转义规则存在差异。
  • 遇到复杂正则怎么排查? → 先拆成小段逐步验证,再确认是不是贪婪、转义或边界符写错了。

技术拓展

一个很实用的写法思路

把复杂正则拆成“片段思维”:

开头约束 + 主体模式 + 分隔符 + 结尾约束

例如邮箱粗校验可以拆成:

  • 开头:^
  • 用户名:[a-zA-Z0-9._%+-]+
  • 分隔符:@
  • 域名:[a-zA-Z0-9.-]+
  • 顶级域:\.[a-zA-Z]{2,}
  • 结尾:$

这样比直接死记整串表达式更容易维护。

Learning Note

本文为个人学习记录,主要来自与 AI 对话后的知识整理与实践总结,仅供个人学习参考。