
前言
在学习正则表达式时,光靠语法记忆往往枯燥难懂,最好的方式就是结合不同语言的实际应用进行练习。由于正则在 Java、JavaScript、Python 三大主流语言中都有完善的支持,我们可以通过统一的案例(如邮箱验证、手机号提取、日期格式转换、注释匹配等),体会到不同语言在 API 调用方式、匹配方法、替换规则 上的差异。本文将分别给出三种语言的完整示例,帮助读者在横向对比中快速掌握正则的实战技巧。
个人主页:尘觉主页
文章目录
- 正则表达式入门与进阶(优化版)
- 1. 概述
- 2. 匹配单个字符
- 元字符 `.`(点)
 
- 3. 匹配一组字符(字符类)
- 4. 常用元字符与空白字符
- 5. 重复与量词
- 6. 位置匹配(边界与锚点)
- 7. 子表达式(分组)与替代(或)
- 8. 回溯引用与替换
- 回溯引用(backreference)
- 替换中使用分组
 
- 9. 前后查找(Lookahead / Lookbehind)
- 正向先行断言(Positive lookahead)`(?=...)`
- 负向先行断言(Negative lookahead)`(?!...)`
- 向后断言(Lookbehind)`(?<=...)` / `(?<!...)`
 
- 10. 嵌入条件与高级用法
- 11. 常见错误与性能提示
- 12. 常用标志(flags)及快速说明
- 13. 常用速查小抄(摘录)
- 14. 练习题(建议动手在 regexr.com 上验证)
- 15. 进阶学习资源
- 16.常见示例
- Java(java.util.regex 示例)
- JavaScript(浏览器 / Node.js)
- 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 示例)
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)
// 验证 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 模块)
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的可以看看这个 
java基础合集
数据库合集
redis合集
nginx合集
linux合集
手写机制
微服务组件
spring_尘觉
springMVC
mybits
等等等还有许多优秀的合集在主页等着大家的光顾感谢大家的支持
欢迎大家加入我的社区 尘觉社区
文章到这里就结束了,如果有什么疑问的地方请指出,诸佬们一起来评论区一起讨论
希望能和诸佬们一起努力,今后我们一起观看感谢您的阅读
如果帮助到您不妨3连支持一下,创造不易您们的支持是我的动力
