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

😀前言

在学习正则表达式时,光靠语法记忆往往枯燥难懂,最好的方式就是结合不同语言的实际应用进行练习。由于正则在 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连支持一下,创造不易您们的支持是我的动力🤞

相关推荐
壹号用户1 天前
python学习之正则表达式
python·学习·正则表达式
xiaozaq1 天前
java 正则表达式 所有的优先级
java·开发语言·正则表达式
ColderYY1 天前
Python中的正则表达式
开发语言·python·正则表达式
李宥小哥1 天前
正则表达式详解
正则表达式
珊瑚礁的猪猪侠4 天前
正则表达式入门到精通教程(Linux实操版)
linux·人工智能·正则表达式
!win !6 天前
分享二个实用正则
javascript·正则表达式
xw56 天前
分享二个实用正则
javascript·正则表达式
刺客-Andy6 天前
Python 第二十节 正则表达式使用详解及注意事项
python·mysql·正则表达式
好好好起个名真难6 天前
正则表达式
正则表达式
坚持就完事了7 天前
正则表达式与Python的re模块
python·正则表达式