实用指南:正则表达式入门与进阶(优化版)

前言
在学习正则表达式时,光靠语法记忆往往枯燥难懂,最好的方式就是结合不同语言的实际应用进行练习。由于正则在 Java、JavaScript、Python 三大主流语言中都有完善的支持,我们可以通过统一的案例(如邮箱验证、手机号提取、日期格式转换、注释匹配等),体会到不同语言在 API 调用方式、匹配方法、替换规则 上的差异。本文将分别给出三种语言的完整示例,帮助读者在横向对比中快速掌握正则的实战技巧。
个人主页:尘觉主页
文章目录
正则表达式入门与进阶(优化版)
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的可以看看这个
等等等还有许多优秀的合集在主页等着大家的光顾感谢大家的支持
欢迎大家加入我的社区 尘觉社区
文章到这里就结束了,如果有什么疑问的地方请指出,诸佬们一起来评论区一起讨论
希望能和诸佬们一起努力,今后我们一起观看感谢您的阅读
如果帮助到您不妨3连支持一下,创造不易您们的支持是我的动力


浙公网安备 33010602011771号