Skip to content

正则表达式 ​

1. 基础概念 ​

正则表达式(Regular Expression, Regex)是一种用于描述字符串模式的表达式,用于搜索、匹配和替换文本。几乎所有主流编程语言都支持正则表达式。

2. 常用元字符 ​

元字符含义
.匹配任意一个字符(除了换行符)
^匹配字符串开头
$匹配字符串结尾
\转义字符,用于匹配特殊字符本身
[]字符集合,匹配其中任意一个字符
[^]非集合,匹配不在集合中的任意一个字符
``
()分组,创建捕获组
\b匹配单词边界
\B匹配非单词边界

3. 量词 ​

量词含义
*匹配 0 次或多次
+匹配 1 次或多次
?匹配 0 次或 1 次
{n}匹配恰好 n 次
{n,}匹配至少 n 次
{n,m}匹配 n 到 m 次

贪婪 / 非贪婪模式 ​

  • 贪婪模式(默认):尽可能多地匹配,如 .*
  • 非贪婪模式:在量词后加 ?,尽可能少地匹配,如 .*?

4. 常见预定义字符类 ​

表达式含义
\d数字 [0-9]
\D非数字 [^0-9]
\w单词字符 [A-Za-z0-9_]
\W非单词字符 [^\w]
\s空白字符(空格、Tab、换行等)
\S非空白字符 [^\s]
\n换行符
\t制表符

5. 分组与引用 ​

  • (abc):捕获组,匹配 "abc" 并捕获内容
  • (?:abc):非捕获组,只分组不捕获
  • \1, \2:反向引用,引用前面捕获的分组内容
  • (?<name>...):命名捕获组(部分语言支持)

示例:

  • 正则:(\d{2})-(\d{2})
  • 匹配:12-34
  • 分组1:12
  • 分组2:34

6. 断言(零宽断言) ​

正向断言 ​

  • (?=...):正向先行断言,匹配后面跟着 ... 的位置
  • (?!...):负向先行断言,匹配后面不是 ... 的位置

反向断言 ​

  • (?<=...):正向后行断言,匹配前面是 ... 的位置
  • (?<!...):负向后行断言,匹配前面不是 ... 的位置

示例:

  • \d+(?=元):匹配后面跟"元"的数字
  • (?<=USD)\d+:匹配前面有"USD"的数字
  • \d{3}(?!\d):匹配后面不是数字的三位数

7. 标志/修饰符 ​

标志含义语言示例
i忽略大小写/pattern/i
g全局匹配/pattern/g
m多行模式/pattern/m
s单行模式(使.匹配换行)/pattern/s

8. 常见应用 ​

  1. 验证邮箱

    regex
    ^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$
  2. 验证手机号(中国大陆)

    regex
    ^1[3-9]\d{9}$
  3. 提取 URL

    regex
    https?://(?:[-\w.]|(?:%[\da-fA-F]{2}))+
  4. 匹配 HTML 标签

    regex
    <([a-zA-Z][a-zA-Z0-9]*)\b[^>]*>(.*?)</\1>
  5. 匹配中文

    regex
    [\u4e00-\u9fa5]
  6. 匹配IP地址

    regex
    ^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$

9. 性能优化技巧 ​

  1. 避免回溯失控:谨慎使用嵌套量词和分支
  2. 使用非捕获组:(?:...)代替(...)提高性能
  3. 具体化匹配:尽量使用具体字符类代替通配符
  4. 锚点优化:使用^和$限定匹配范围
  5. 避免重复编译:在循环外预编译正则表达式

10. 工具推荐 ​

  • Regex101 - 在线调试和测试工具
  • RegExr - 可视化学习和测试工具
  • Regexper - 正则表达式可视化工具
  • Debuggex - 实时正则表达式调试器

11. 各语言正则支持 ​

  • Python: re模块,支持命名组和注释
  • JavaScript: 原生支持,使用/pattern/flags语法
  • Java: java.util.regex包,支持命名组
  • PHP: preg_系列函数,支持PCRE语法

总结 ​

正则表达式强大但需要谨慎使用:

  • 复杂正则最好添加注释或分段构建,增强可读性
  • 注意贪婪匹配可能导致的性能问题和意外结果
  • 测试边界情况,确保正则表达式的健壮性
  • 考虑使用正则表达式库的高级特性(如递归匹配、条件表达式)
  • 在不需要捕获内容时使用非捕获组提升性能

记住:有些问题用字符串函数解决更简单,不要过度依赖正则表达式。