
😀前言
在学习正则表达式时,光靠语法记忆往往枯燥难懂,最好的方式就是结合不同语言的实际应用进行练习。由于正则在 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)
(?<=...)
/(?<!...)
)
- [正向先行断言(Positive lookahead)`(?=...)`](#正向先行断言(Positive lookahead)
- [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
能匹配 CyC2018
、C C2018
(中间任何单字符),但不能匹配 C\nC2018
(换行)。
3. 匹配一组字符(字符类)
字符类用方括号 [...]
表示,表示"匹配其中任意一个字符"。
- 范围写法
a-z
、0-9
基于字符的编码顺序(通常是 ASCII)。 -
在方括号内用作范围,若要表示字符-
本身,放到开头或末尾或转义。- 方括号内的
^
表示取反(例如[^0-9]
表示非数字字符)。
示例:
-
要匹配以
abc
开头,且接着的一个字符不是数字并且整行结束:- 正则:
^abc[^0-9]$
- 说明:
^
和$
锚定整行(更多见第6节)。 - 匹配:
abcd
、abca
;不匹配 :abc1
、abc12
。
- 正则:
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}
能匹配 1900
、2010
、但不会匹配 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,使用更紧凑且不会把 255
、999
等错误匹配为合法。
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. 常见错误与性能提示
- 忘记转义特殊字符 :如要匹配
.
、*
、+
、?
、(
、)
、[
、]
、{
、}
、\
等,需要加\
。例如\.
匹配点号。 - 使用贪婪量词造成"吞并"更多文本 :如
a.*b
在a...a...b
中可能匹配到最后的b
,改用懒惰a.*?b
或更精确的类。 - 回溯和性能陷阱(catastrophic backtracking) :复杂的嵌套量词(如
(a+)+
)在长文本上可能非常慢。避免不必要的回溯,或使用原子组/占有量词(部分引擎支持)来降低风险。 - 不同引擎差异 :不要假设所有正则特性在所有环境都可用(例如 lookbehind、命名捕获、条件表达式、
\u
/\l
替换等)。
性能建议:用字符类替代 .
(更精确),先限定长度({m,n}
),必要时使用非捕获组 (?:...)
或原子组提升效率。
12. 常用标志(flags)及快速说明
标志 | 名称 | 含义 |
---|---|---|
i |
ignore case | 忽略大小写匹配 |
m |
multiline | ^ 和 $ 匹配每行的开始/结尾(而不是整个文本) |
s |
dotall / singleline | 让 . 可以匹配换行符 |
x |
verbose | 允许在正则中写空格和注释(可读性更好,需按语法使用) |
写法示例(不同环境写法不同):
- JavaScript:
/pattern/i
或new 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 上验证)
- 找出文本中以单词
cat
开头但不是cats
的单词(例如cat
、cater
匹配,但cats
不匹配)。 - 将
2020/01/02
格式的日期替换为2020-01-02
。 - 匹配合法 IPv4 地址(0.0.0.0 到 255.255.255.255)。
15. 进阶学习资源
- regexr(在线交互): https://regexr.com/
- Regular-Expressions.info(深入教程)
- 各语言的标准库文档(Python
re
、Javajava.util.regex
、JavaScriptRegExp
)
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 借助
Pattern
和Matcher
提供强大但相对繁琐的接口,适合构建复杂匹配逻辑; - JavaScript 以字面量和
RegExp
对象为核心,结合字符串方法test
、match
、replace
,在前端与 Node.js 场景中使用最为灵活; - Python 通过
re
模块提供直观的search
、findall
、sub
等函数,语法简洁,适合数据处理与脚本开发。
通过三个示例的对比,可以看到虽然语法一致,但各语言的风格迥异。掌握这些差别,不仅能提高正则使用效率,还能在跨语言开发中快速迁移经验,正则表达式作为一把"文本处理的瑞士军刀",只要善加练习,必能在日志分析、数据清洗、表单校验等场景中发挥巨大作用。
😁热门专栏推荐
想学习vue的可以看看这个
等等等还有许多优秀的合集在主页等着大家的光顾感谢大家的支持
🤔欢迎大家加入我的社区 尘觉社区
文章到这里就结束了,如果有什么疑问的地方请指出,诸佬们一起来评论区一起讨论😁
希望能和诸佬们一起努力,今后我们一起观看感谢您的阅读🍻
如果帮助到您不妨3连支持一下,创造不易您们的支持是我的动力🤞
