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

从入门到"瞎眼"

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

  • 匹配数字:[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] 匹配不是 123 的任意一个字符
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 ba b

\S

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

.

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

?

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

\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*""aaaaaa...

+

  • 含义 :匹配前面子表达式 一次或多次
    • 例:a+aaaaaa...

?

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

.

  • 含义 :匹配除换行符 \n 之外的 任意单个字符
    • 例:a.c → 匹配 abca-ca1c

[]

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

{}

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

|

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

\

  • 含义:转义符。

  • 作用

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

正则表达式修饰符(Flags)

i

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

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可不准哦

相关推荐
XiaoSong10 小时前
React 表单组件深度解析
前端·react.js
薛定谔的算法10 小时前
标准盒模型与怪异盒模型:前端布局中的“快递盒子”公摊问题
前端·css·trae
stroller_1210 小时前
React 事件监听踩坑:点一次按钮触发两次请求?原因竟然是这个…
前端
文艺理科生10 小时前
Nuxt 应用安全与认证:构建企业级登录系统
前端·javascript·后端
彭于晏爱编程10 小时前
🌍 丝滑前端国际化:React + i18next 六语言实战
前端
哈哈地图10 小时前
前端sdk相关技术汇总
前端·sdk·引擎
光影少年10 小时前
webpack打包优化都有哪些
前端·webpack·掘金·金石计划
JunjunZ10 小时前
Vue项目使用天地图
前端·vue.js
芜青10 小时前
ES6手录02-字符串与函数的扩展
前端·javascript·es6