正则表达式入门与进阶(优化版)

😀前言

在学习正则表达式时,光靠语法记忆往往枯燥难懂,最好的方式就是结合不同语言的实际应用进行练习。由于正则在 Java、JavaScript、Python 三大主流语言中都有完善的支持,我们可以通过统一的案例(如邮箱验证、手机号提取、日期格式转换、注释匹配等),体会到不同语言在 API 调用方式、匹配方法、替换规则 上的差异。本文将分别给出三种语言的完整示例,帮助读者在横向对比中快速掌握正则的实战技巧。


🏠个人主页:尘觉主页

文章目录

  • 正则表达式入门与进阶(优化版)
    • [1. 概述](#1. 概述)
    • [2. 匹配单个字符](#2. 匹配单个字符)
      • [元字符 `.`(点)](#元字符 .(点))
    • [3. 匹配一组字符(字符类)](#3. 匹配一组字符(字符类))
    • [4. 常用元字符与空白字符](#4. 常用元字符与空白字符)
    • [5. 重复与量词](#5. 重复与量词)
    • [6. 位置匹配(边界与锚点)](#6. 位置匹配(边界与锚点))
    • [7. 子表达式(分组)与替代(或)](#7. 子表达式(分组)与替代(或))
    • [8. 回溯引用与替换](#8. 回溯引用与替换)
    • [9. 前后查找(Lookahead / Lookbehind)](#9. 前后查找(Lookahead / Lookbehind))
      • [正向先行断言(Positive lookahead)`(?=...)`](#正向先行断言(Positive lookahead)(?=...))
      • [负向先行断言(Negative lookahead)`(?!...)`](#负向先行断言(Negative lookahead)(?!...))
      • [向后断言(Lookbehind)`(?<=...)` / `(?<!...)`](#向后断言(Lookbehind)(?<=...) / (?<!...))
    • [10. 嵌入条件与高级用法](#10. 嵌入条件与高级用法)
    • [11. 常见错误与性能提示](#11. 常见错误与性能提示)
    • [12. 常用标志(flags)及快速说明](#12. 常用标志(flags)及快速说明)
    • [13. 常用速查小抄(摘录)](#13. 常用速查小抄(摘录))
    • [14. 练习题(建议动手在 regexr.com 上验证)](#14. 练习题(建议动手在 regexr.com 上验证))
    • [15. 进阶学习资源](#15. 进阶学习资源)
    • 16.常见示例
      • [Java(java.util.regex 示例)](#Java(java.util.regex 示例))
      • [JavaScript(浏览器 / Node.js)](#JavaScript(浏览器 / Node.js))
      • [Python(re 模块)](#Python(re 模块))
    • 😄总结

正则表达式入门与进阶(优化版)

1. 概述

正则表达式(regular expression,简称 regex)是描述文本模式的一种紧凑语法,常用于查找、匹配、验证与替换文本。它不是独立的程序,而是内嵌在很多编程语言、编辑器、工具和库中(如 Java、JavaScript、Python、Perl、grep、VSCode、Sublime Text 等)。

在线练习与调试工具:https://regexr.com/。

使用正则时,先想清要匹配的"模式"------是精确匹配、还是模糊匹配?是否需要整行/整词匹配?是否需要忽略大小写?先把需求拆成小句子,再把每句翻译成正则语法。


2. 匹配单个字符

元字符 .(点)

  • . 可以匹配除了换行符之外的任意单个字符 (不同引擎中可通过 s/DOTALL 标志让 . 也匹配换行)。
  • 它是元字符,如果要匹配字符 . 本身,需要转义:\.

示例 :正则 C.C2018 能匹配 CyC2018C C2018(中间任何单字符),但不能匹配 C\nC2018(换行)。


3. 匹配一组字符(字符类)

字符类用方括号 [...] 表示,表示"匹配其中任意一个字符"。

  • 范围写法 a-z0-9 基于字符的编码顺序(通常是 ASCII)。
  • - 在方括号内用作范围,若要表示字符 - 本身,放到开头或末尾或转义。
  • 方括号内的 ^ 表示取反(例如 [^0-9] 表示非数字字符)。

示例

  • 要匹配以 abc 开头,且接着的一个字符不是数字并且整行结束

    • 正则:^abc[^0-9]$
    • 说明:^$ 锚定整行(更多见第6节)。
    • 匹配:abcdabca不匹配abc1abc12

4. 常用元字符与空白字符

元字符 含义 说明
\d 数字字符 等价于 [0-9](在 Unicode 模式下含义可能拓展)
\D 非数字 等价于 [^0-9]
\w 单词字符 通常等价 [A-Za-z0-9_](在 Unicode 模式下会有扩展)
\W 非单词字符 \w 的取反
\s 空白字符 等价 `[

](包含制表、换行等) | | \S| 非空白字符 |\s` 的取反 |

注意:[\b] 在字符类里表示 退格(backspace)字符 ,而单独的 \b 表示单词边界(见第6节)。

额外:\xNN 表示十六进制字符,例如 \x0A 是 ASCII 的 Line Feed(即 \n)。一些引擎也支持八进制写法如 \0nn


5. 重复与量词

  • *:匹配 0 次或多次(贪婪)
  • +:匹配 1 次或多次(贪婪)
  • ?:匹配 0 次或 1 次
  • {n}:精确匹配 n 次
  • {m,n}:匹配 m 到 n 次
  • {m,}:至少 m 次

贪婪 vs 懒惰

  • 默认量词是贪婪 (尽可能多匹配)。加 ? 可变为懒惰(尽可能少匹配)。

示例

  • 正则 a.+c 对文本 abcabcabc 会匹配整段 abcabcabc(因为 .+ 向右尽量多匹配);
  • 若使用 a.+?c(懒惰),则先匹配最短的 abc

电子邮箱示例(简单)

复制代码
[\w.]+@\w+\.\w+

说明:[\w.]+ 表示用户名部分允许字母数字下划线和点,+ 表示出现一次或多次。注意:真实世界的 Email 规范更复杂,这只是常见的简单匹配写法。


6. 位置匹配(边界与锚点)

  • \b:单词边界------匹配位置(不消耗字符),出现在 \w\W 或字符串边界之间。
  • \B:非单词边界。
  • ^:行/字符串开头(在多行模式下,匹配每行开头)。
  • $:行/字符串结尾(在多行模式下,匹配每行结尾)。

示例 :匹配以 // 开头的注释行(允许前面有空白):

复制代码
^\s*//.*$

下面插入的图片保持不变(您之前的图片不动):


7. 子表达式(分组)与替代(或)

  • 用圆括号 (...) 定义子表达式(捕获分组),分组可以作为整体使用量词。
  • 非捕获分组:(?:...),只用来分组但不保存匹配内容(节省编号)。
  • | 表示"或"运算。

示例:匹配年份

复制代码
(?:19|20)\d{2}

能匹配 19002010、但不会匹配 1020(前两位必须是 19 或 20)。

示例:匹配 IP(更稳健的写法)

复制代码
((25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)\.){3}(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)

说明:每一段允许 0-255,使用更紧凑且不会把 255999 等错误匹配为合法。


8. 回溯引用与替换

回溯引用(backreference)

  • 在正则里,\1\2 等表示对前面第 1、2 个捕获组匹配结果的引用(匹配文本时使用)。

示例:匹配 HTML 的开始和结束标签且保证标签名一致:

复制代码
<(h[1-6])>.*?<\/\1>

说明:(h[1-6]) 捕获标签名(如 h1),<\/\1> 要求结束标签与开始标签一致。

替换中使用分组

  • 在替换字符串中,不同引擎用法不同:常见有 $1\1(替换文本)两种形式。

电话格式化示例

  • 文本:313-555-1234
  • 查找:(\d{3})(-)(\d{3})(-)(\d{4})
  • 替换:($1) $3-$5
  • 结果:(313) 555-1234

注意 :大小写转换(例如 \U/\L)是否支持取决于你使用的工具或语言(例如 Perl 或一些文本编辑器支持,但并非通用)。


9. 前后查找(Lookahead / Lookbehind)

正向先行断言(Positive lookahead)(?=...)

匹配某位置前面必须跟着 ...,但 ... 不计入匹配结果。

示例 :取出 @ 之前的用户名:

复制代码
\w+(?=@)

abc@qq.com 上会匹配 abc

负向先行断言(Negative lookahead)(?!...)

表示后面不能是 ...

向后断言(Lookbehind)(?<=...) / (?<!...)

  • 向后断言检查当前匹配的左边上下文(并不计入匹配结果)。
  • 注意:并非所有引擎都支持固定宽度以外的 lookbehind(比如历史上的 JavaScript 就曾不支持 lookbehind,但现代大多数浏览器引擎已经支持)。

示例(可选) :匹配 5 位邮编,且若后面有 - 时再匹配后续 4 位:

复制代码
\d{5}(?(?=-)-\d{4})

(这是条件写法的一个示例,非所有引擎都支持)


10. 嵌入条件与高级用法

一些正则引擎(如 PCRE)支持条件表达式 (?( 条件 )yes|no),条件可以是某个捕获组是否匹配,或是某个正向断言是否成立。示例:

复制代码
(\()?abc(?(1)\))

说明:如果第 1 组 \( 匹配(也就是字符串以 ( 开头),则要求末尾也有 ),所以能匹配 (abc)abc,但不能只匹配 (abc

这类语法属于高级特性,初学者可以先熟练掌握分组、回溯引用、断言再学习条件表达式。


11. 常见错误与性能提示

  1. 忘记转义特殊字符 :如要匹配 .*+?()[]{}\ 等,需要加 \。例如 \. 匹配点号。
  2. 使用贪婪量词造成"吞并"更多文本 :如 a.*ba...a...b 中可能匹配到最后的 b,改用懒惰 a.*?b 或更精确的类。
  3. 回溯和性能陷阱(catastrophic backtracking) :复杂的嵌套量词(如 (a+)+)在长文本上可能非常慢。避免不必要的回溯,或使用原子组/占有量词(部分引擎支持)来降低风险。
  4. 不同引擎差异 :不要假设所有正则特性在所有环境都可用(例如 lookbehind、命名捕获、条件表达式、\u/\l 替换等)。

性能建议:用字符类替代 .(更精确),先限定长度({m,n}),必要时使用非捕获组 (?:...) 或原子组提升效率。


12. 常用标志(flags)及快速说明

标志 名称 含义
i ignore case 忽略大小写匹配
m multiline ^$ 匹配每行的开始/结尾(而不是整个文本)
s dotall / singleline . 可以匹配换行符
x verbose 允许在正则中写空格和注释(可读性更好,需按语法使用)

写法示例(不同环境写法不同):

  • JavaScript:/pattern/inew RegExp('pattern', 'i')
  • Python:re.compile(r'pattern', re.IGNORECASE)

13. 常用速查小抄(摘录)

  • 字符类:[abc], [^abc], [a-z]
  • 预定义类:\d, \w, \s, \D, \W, \S
  • 量词:*, +, ?, {n}, {m,n}
  • 边界:^, $, \b, \B
  • 组与引用:(...), (?:...), \1(回溯引用)
  • 断言:(?=...), (?!...), (?<=...), (?<!...)

14. 练习题(建议动手在 regexr.com 上验证)

  1. 找出文本中以单词 cat 开头但不是 cats 的单词(例如 catcater 匹配,但 cats 不匹配)。
  2. 2020/01/02 格式的日期替换为 2020-01-02
  3. 匹配合法 IPv4 地址(0.0.0.0 到 255.255.255.255)。

15. 进阶学习资源


16.常见示例

Java(java.util.regex 示例)

java 复制代码
import java.util.regex.*;

public class RegexJavaDemo {
    public static void main(String[] args) {
        String text = "Contact: 313-555-1234 or email abc.def@qq.com";

        // 1) 验证:简单的邮箱检查(注意 matches 要完全匹配整个字符串)
        Pattern email = Pattern.compile("[\\w.]+@\\w+\\.\\w+");
        Matcher m1 = email.matcher("abc.def@qq.com");
        System.out.println("is email: " + m1.matches());

        // 2) 查找并提取:找到文本中的电话并格式化
        Pattern phone = Pattern.compile("(\\d{3})-(\\d{3})-(\\d{4})");
        Matcher m2 = phone.matcher(text);
        if (m2.find()) {
            String formatted = String.format("(%s) %s-%s", m2.group(1), m2.group(2), m2.group(3));
            System.out.println("phone: " + formatted);
        }

        // 3) 替换:把日期 2020/01/02 替换为 2020-01-02
        String dateText = "Date: 2020/01/02";
        String replaced = dateText.replaceAll("(\\d{4})/(\\d{2})/(\\d{2})", "$1-$2-$3");
        System.out.println(replaced);
    }
}

JavaScript(浏览器 / Node.js)

js 复制代码
// 验证 email
const emailRe = /[\w.]+@\w+\.\w+/;
console.log(emailRe.test('abc.def@qq.com')); // true

// 提取并格式化电话
const text = 'Contact: 313-555-1234 or email abc.def@qq.com';
const phoneRe = /(\d{3})-(\d{3})-(\d{4})/;
const phoneMatch = text.match(phoneRe);
if (phoneMatch) {
  const formatted = `(${phoneMatch[1]}) ${phoneMatch[2]}-${phoneMatch[3]}`;
  console.log('phone:', formatted);
}

// 全局替换日期格式
const dateText = 'Date: 2020/01/02';
const replaced = dateText.replace(/(\d{4})\/(\d{2})\/(\d{2})/, '$1-$2-$3');
console.log(replaced);

// 多行注释匹配(使用 m 标志)
const lines = ' // comment\n var x = 1; // another';
const commentRe = /^\s*\/\/.*$/gm;
console.log(lines.match(commentRe)); // 返回匹配注释的行

Python(re 模块)

py 复制代码
import re

text = 'Contact: 313-555-1234 or email abc.def@qq.com'

# 验证(fullmatch 要求整个字符串匹配)
email_re = re.compile(r'[\w.]+@\w+\.\w+')
print(bool(email_re.fullmatch('abc.def@qq.com')))

# 查找并提取电话
phone_re = re.compile(r'(\d{3})-(\d{3})-(\d{4})')
m = phone_re.search(text)
if m:
    formatted = f'({m.group(1)}) {m.group(2)}-{m.group(3)}'
    print('phone:', formatted)

# 替换日期格式
date_text = 'Date: 2020/01/02'
replaced = re.sub(r'(\d{4})/(\d{2})/(\d{2})', r'\1-\2-\3', date_text)
print(replaced)

# 多行注释匹配
lines = ' // comment\n var x = 1; // another'
comment_re = re.compile(r'^\s*//.*$', re.MULTILINE)
print(comment_re.findall(lines))

😄总结

正则表达式的语法几乎跨语言通用,但在 调用方式细节差异 上各有特点:

  • Java 借助 PatternMatcher 提供强大但相对繁琐的接口,适合构建复杂匹配逻辑;
  • JavaScript 以字面量和 RegExp 对象为核心,结合字符串方法 testmatchreplace,在前端与 Node.js 场景中使用最为灵活;
  • Python 通过 re 模块提供直观的 searchfindallsub 等函数,语法简洁,适合数据处理与脚本开发。

通过三个示例的对比,可以看到虽然语法一致,但各语言的风格迥异。掌握这些差别,不仅能提高正则使用效率,还能在跨语言开发中快速迁移经验,正则表达式作为一把"文本处理的瑞士军刀",只要善加练习,必能在日志分析、数据清洗、表单校验等场景中发挥巨大作用。

😁热门专栏推荐
想学习vue的可以看看这个

java基础合集

数据库合集

redis合集

nginx合集

linux合集

手写机制

微服务组件

spring_尘觉

springMVC

mybits

等等等还有许多优秀的合集在主页等着大家的光顾感谢大家的支持

🤔欢迎大家加入我的社区 尘觉社区

文章到这里就结束了,如果有什么疑问的地方请指出,诸佬们一起来评论区一起讨论😁

希望能和诸佬们一起努力,今后我们一起观看感谢您的阅读🍻

如果帮助到您不妨3连支持一下,创造不易您们的支持是我的动力🤞

相关推荐
AI悦创|编程1v11 天前
00-1-正则表达式学习心得:从入门到上瘾,再到克制
数据仓库·正则表达式·数据挖掘·ai悦创编程一对一教学·python一对一辅导·python一对一教学
带土11 天前
PHP 中的正则表达式
正则表达式·php
taller_20002 天前
VBA之正则表达式(45)-- 拆分材料和规格
正则表达式·正则·数据清洗·提取数据·材料规格
光明磊2 天前
正则表达式Regex
正则表达式
AI悦创|编程1v12 天前
01-元字符:如何巧妙记忆正则表达式的基本元件?
正则表达式·ai悦创编程一对一教学·python一对一辅导·python一对一教学
課代表3 天前
Acrobat DC 文本域表单验证中的 js 使用
javascript·正则表达式·表单验证·数据完整性·字段验证·事件对象·自定义验证
风语者6666 天前
perl踩坑系列===正则表达式第2坑---split中的“或”操作符
开发语言·正则表达式·perl
AI悦创|编程1v18 天前
00-为什么要系统学习正则表达式?
学习·正则表达式·python一对一辅导·python一对一教学
叫我詹躲躲9 天前
别再手写正则了!20 + 证件 / 手机号 / 邮箱验证函数,直接复制能用
前端·javascript·正则表达式