这么全的正则,还不收藏?

从入门到"瞎眼"

最初的正则写法,简直是小学生数学:

  • 匹配数字:[0-9]
  • 匹配字母:[a-zA-Z]
  • 匹配单词:\w+

简单直观,还能说得清。

结果有一天,你在项目里看到这么一坨:

ruby 复制代码
^(?=.*[A-Z])(?=.*\d)[A-Za-z\d!@#$%^&*]{8,}$

你大概会愣住:这不是我认识的正则!

原来别人用了一堆零宽断言,写了个"密码强度验证",瞬间从"简单匹配"变成了"暗黑魔法"。


当正则开始玩心理战

正则真正的杀伤力,不是写出来,而是读别人写的。

比如说,以下两个表达式都能验证邮箱:

ini 复制代码
^[^@\s]+@[^@\s]+.[^@\s]+$
ruby 复制代码
^(?=.{1,64}@.{4,255}$)(?=.{6,})([A-Za-z0-9._%+-]+)@([A-Za-z0-9.-]+).([A-Za-z]{2,})$

前者"能用",后者"较严谨",但阅读体验完全不同。

有些人甚至会把正则写成一幅 艺术品,加上各种嵌套、条件分支,让你怀疑人生。


锚点(Anchors)

  • ^ :匹配字符串的 开始 如果写在中间位置,需要转义 \^ 才能表示字面量 ^。
  • $ :匹配字符串的 结束
正则 意义
^123 匹配以 123 开头的字符串
[^123] 匹配不是 1、2、3 的任意一个字符
123$ 匹配以 123 结尾的字符串

常用占位符(Metacharacters)

\d

  • 含义 :匹配一个数字 [0-9]
  • 例子 :\d{3} → 匹配任意三位数字,如 123

\D

  • 含义:匹配一个非数字字符
  • 例子 :\D+ → 匹配连续的非数字,如 abc

\w

  • 含义 :匹配一个单词字符(字母、数字或下划线 [A-Za-z0-9_])
  • 例子 :\w+ → 匹配单词,如 hello_123

\W

  • 含义:匹配一个非单词字符
  • 例子 :\W+ → 匹配标点或符号,如 !@#

\s

  • 含义:匹配一个空白符(空格、换行、制表符等)
  • 例子 :a\s+b → 匹配 a b、a b

\S

  • 含义:匹配一个非空白符
  • 例子 :\S+ → 匹配非空字符序列

.

  • 含义 :匹配除换行符 \n 之外的任意单字符
  • 例子 :a.c → 匹配 abc、a-c、a1c

?

  • 含义:表示前一个子表达式可有可无(0 次或 1 次);也可用于懒惰匹配
  • 例子 :colou?r → 匹配 color 或 colour

\n

  • 含义:匹配一个换行符
  • 例子 :foo\nbar → 匹配 foo 换行后接 bar

\t

  • 含义:匹配一个制表符
  • 例子 :\t123 → 匹配前面有一个 Tab 的 123

\b

  • 含义:匹配一个单词边界(单词与空白/符号之间的位置)
  • 例子 :\bcat\b → 匹配完整的 cat,不匹配 concatenate

\B

  • 含义:匹配一个非单词边界
  • 例子 :\Bcat\B → 匹配在单词中间出现的 cat,如 concatenate

示例:匹配 QQ 邮箱
regex 复制代码
/^[1-9][0-9]{5,11}@qq\.com$/
# 正则表达式量词总结

量词

*

  • 语法 :\d*
  • 含义 :数字可以出现 0 次或任意多次(包括不出现)。

+

  • 语法 :\d+
  • 含义 :数字至少出现 1 次,可以出现多次。

?

  • 语法 :\d?
  • 含义 :数字 出现 0 次或 1 次。

{n}

  • 语法 :\d{2}
  • 含义 :数字必须 恰好出现 n 次(此处为 2 次)。

{n,m}

  • 语法 :\d{2,4}
  • 含义 :数字至少出现 n 次 ,至多出现 m 次(此处为 2--4 次)。

{n,}

  • 语法 :\d{3,}
  • 含义 :数字至少出现 n 次(此处为 ≥3 次)。

⚠️ 注意 :

这些量词本身不能直接跟数字写在一起,否则会被解释成数量,而不是正则语法。

例如:

  • 正确:\d{2,4}
  • 错误:\d2,4

正则表达式常用符号速查表

^

  • 含义 :匹配输入字符串的 开始位置。
  • 特殊情况 :在 [] 中使用表示 非 (取反)。
    • 例:^[A-Z] → 以大写字母开头
    • 例:[^0-9] → 非数字

$

  • 含义 :匹配输入字符串的 结尾位置。
  • 多行模式 :当设置 m (multiline) 标志时,$ 也可以匹配换行符前的位置。
    • 例:abc$ → 以 "abc" 结尾的字符串

()

  • 含义:标记一个子表达式的开始和结束。

  • 作用 :

    1. 分组:将多个字符当成一个整体。
    2. 捕获:匹配到的子串可用于后续引用。
    • 例:(abc|bac|acd) → 匹配三者之一

*

  • 含义 :匹配前面子表达式 零次或多次 。
    • 例:a* → ""、a、aa、aaa...

+

  • 含义 :匹配前面子表达式 一次或多次 。
    • 例:a+ → a、aa、aaa...

?

  • 含义 :匹配前面子表达式 零次或一次 ;或作为 非贪婪限定符 (*? / +?)。
    • 例:a? → ""、a

.

  • 含义 :匹配除换行符 \n 之外的 任意单个字符 。
    • 例:a.c → 匹配 abc、a-c、a1c 等

[]

  • 含义 :定义一个 字符类,匹配方括号中的任意一个字符。
  • 取反 :[^...] 表示不在集合内的任意一个字符。
    • 例:[abc] → 匹配 a、b 或 c
    • 例:[^0-9] → 匹配非数字

{}

  • 含义:标记限定符,指定前面子表达式的重复次数。
  • 语法 :
    • {n} → 恰好 n 次
    • {n,m} → n 到 m 次
    • {n,} → 至少 n 次
    • 例:\d{2,4} → 2 到 4 位数字

|

  • 含义 :逻辑"或",匹配两个表达式中的一个。
    • 例:cat|dog → 匹配 cat 或 dog

\

  • 含义:转义符。

  • 作用 :

    1. 将特殊字符转为普通字符:\. → 匹配点号本身
    2. 表示特殊序列:\d 数字,\w 单词字符,\s 空白
    3. 表示反向引用:\1 → 引用第一个捕获组
    • 例:a\. → 匹配 a.
    • 例:(\d)\1 → 匹配连续两个相同数字

正则表达式修饰符(Flags)

i

  • 含义:不区分大小写匹配。
  • 例子 :/abc/i → 匹配 abc、ABC、AbC

m

  • 含义:多行模式。
  • 效果 :^ 和 $ 不仅匹配整个字符串的开头和结尾,还能匹配每一行的开头和结尾。
  • 例子 :/^abc/m → 在多行文本中匹配行首的 abc

s

  • 含义 :单行模式,使 . 可以匹配包括换行符在内的所有字符。
  • 例子 :/a.b/s → 匹配 a 换行 b

u

  • 含义 :启用 Unicode 模式,正确处理 Unicode 字符(如 emoji、特殊符号)。
  • 例子 :/^\p{L}+$/u → 匹配所有 Unicode 字母

y

  • 含义 :粘性匹配,从字符串的当前位置开始匹配,不会跳过字符。

  • 例子 :

    js 复制代码
    const r = /\d/y;
    r.lastIndex = 2;
    console.log(r.test("12")); // false,因为不会回溯

预查

?!

  • 名称:负向先行断言(Negative Lookahead)

  • 含义 :匹配某个位置,要求 后面 的内容不满足条件。

  • 示例 :

    ini 复制代码
    const str = "photo.jpg image.jpg doc.txt";
    str.match(/[a-z]+[.]+(?!jpg)/g); // ["doc."]

?<=

  • 名称:正向后行断言(Positive Lookbehind)

  • 含义 :匹配某个位置,要求 前面 的内容满足条件。

  • 示例 :

    python 复制代码
    const str = "photo.jpg image.jpg";
    str.match(/\w+(?<=\w).jpg/g); // ["photo.jpg", "image.jpg"]

?<!

  • 名称:负向后行断言(Negative Lookbehind)

  • 含义 :匹配某个位置,要求 前面 的内容不满足条件。

  • 示例 :

    ini 复制代码
    const str = "photo.jpg image.jpg";
    str.match(/\w+(?<!photo).jpg/g); // ["image.jpg"]

贪婪(Greedy)

  • 定义 :量词(* + {n,m} 等)默认是 贪婪的,会尽可能多地匹配字符。

  • 示例 :

    js 复制代码
    const str = "<div>content</div><div>test</div>";
    str.match(/<div>.*<\/div>/); 
    // 结果: ["<div>content</div><div>test</div>"]
    // 贪婪匹配,把中间的所有内容都吃掉了

惰性(Lazy / Reluctant)

  • 定义 :在量词后加 ?(如 *? +? {n,m}?),会变成 惰性匹配,尽可能少地匹配字符。

  • 示例 :

    js 复制代码
    const str = "<div>content</div><div>test</div>";
    str.match(/<div>.*?</div>/g);
    // 结果: ["<div>content</div>", "<div>test</div>"]
    // 惰性匹配,逐段匹配,不会一次性吞掉所有

怎么与安全的使用正则

正则就像一把双刃剑:

  • 用得好:简洁、强大、跨语言通用,一行搞定复杂逻辑。
  • 用得烂:可读性差、性能糟糕、出 bug 难调试,团队没人敢维护。

于是有人调侃:

"正则就是程序员的黑魔法:写的时候感觉自己是神,过几个月回头看,感觉自己是受害者。"


  1. 写注释:复杂表达式最好分段解释。

    ruby 复制代码
    ^(?=.*[A-Z])   # 至少一个大写字母
    (?=.*\d)       # 至少一个数字
    [A-Za-z\d]{8,}$ # 总长度≥8
  2. 拆逻辑:别硬要一个正则全搞定,允许前后分步校验。

  3. 工具辅助 :用 regex101.com 这种网站实时调试。

  4. 团队约定:常用正则做成函数封装,别到处复制粘贴。

  5. AI审查 :使用AI工具验证有些AI可不准哦。

相关推荐
架构技术专栏1 小时前
Agent 工具调用:从工具声明到执行反馈
前端·人工智能·后端
别动我齐刘海2 小时前
C++ 工程化学习
java·linux·前端·c++·学习·机器学习·机器人
志尊宝3 小时前
Vue3 零基础每日笔记(071):暗黑模式与主题切换——CSS 变量 + Element Plus 暗黑方案
前端·css·笔记·vue·html·前端开发·软件开发
刘发财3 小时前
前端如何生成10000页PDF文件?
前端·javascript·开源
A接拉起0074 小时前
2026 年 JavaScript 开发者需要了解的知识
前端·javascript·后端
_馒头4 小时前
pixiJs游戏开发实践 - 跳棋小游戏
javascript·vue.js
用户11481867894844 小时前
面试官:大屏项目里十几个模块同时渲染上万条数据,怎么做到不卡?
前端·性能优化
前端市界4 小时前
Pro React Admin: 统一工程底座,承载多种应用...
前端·github
葡萄城技术团队4 小时前
dsh-spreadjs-editor 当前支持什么:安装前需要了解的几件事
前端
三*一4 小时前
优化修整算法
前端·javascript·算法