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

从入门到"瞎眼"

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

  • 匹配数字:[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可不准哦

相关推荐
木觞清21 分钟前
补环境-JS原型链检测:在Node.js中完美模拟浏览器原型环境
开发语言·javascript·node.js
我是华为OD~HR~栗栗呀23 分钟前
华为od-前端面经-22届非科班
java·前端·c++·后端·python·华为od·华为
知识分享小能手24 分钟前
React学习教程,从入门到精通,React Router 语法知识点及使用方法详解(28)
前端·javascript·学习·react.js·前端框架·vue·react
黄毛火烧雪下27 分钟前
React中Class 组件 vs Hooks 对照
前端·javascript·react.js
gnip1 小时前
工作常用设计模式
前端·javascript
前端达人2 小时前
「React实战面试题」useEffect依赖数组的常见陷阱
前端·javascript·react.js·前端框架·ecmascript
开开心心就好2 小时前
PDF清晰度提升工具,让模糊文档变清晰
java·服务器·前端·python·智能手机·pdf·ocr
路修远i2 小时前
灰度和红蓝区
前端
路修远i2 小时前
cursor rules 实践
前端·cursor