正则表达式总结

一、正则表达式简介

正则表达式(Regular Expression)是一种用于匹配字符串中字符组合的模式,广泛应用于文本处理、数据验证、搜索替换等领域。通过特定的字符和符号组合来定义匹配规则,能够高效地对字符串进行复杂的匹配和操作。

正则表达式引擎会从左到右扫描目标字符串,试图找到与正则表达式模式匹配的文本片段。当找到匹配时,会返回匹配的文本内容或根据指定的操作(如替换)进行处理。

二、基本语法

(一)字符匹配

表达式 描述 示例及说明
. 匹配任意单个字符(除换行符\n外) a.b 可以匹配 a1ba2ba b
[abc] 匹配方括号内的任意一个字符 [abc] 可以匹配 abc
[a-z] 匹配指定范围内的任意一个字符 [a-z] 可以匹配任意一个小写字母
[^abc] 匹配不在方括号内的任意一个字符 [^abc] 可以匹配除 abc 之外的任意字符
\d 匹配任意数字,等价于 [0-9] \d 可以匹配 019
\w 匹配任意字母或数字或下划线,等价于 [A-Za-z0-9_] \w 可以匹配 aB7_
\s 匹配任意空白字符,包括空格、制表符、换页符等 \s 可以匹配空格、\t\f
\D 匹配任意非数字,等价于 [^0-9] \D 可以匹配 a@#
\W 匹配任意非字母数字下划线,等价于 [^A-Za-z0-9_] \W 可以匹配 @#%
\S 匹配任意非空白字符 \S 可以匹配 a7@

(二)数量匹配

表达式 描述 示例及说明
* 匹配前面的字符或子模式零次或多次 a* 可以匹配 ""(空字符串)、aaa
+ 匹配前面的字符或子模式一次或多次 a+ 可以匹配 aaa 等,但不能匹配空字符串
? 匹配前面的字符或子模式零次或一次 a? 可以匹配 ""(空字符串)或 a
{n} 匹配前面的字符或子模式恰好 n a{3} 可以匹配 aaa
{n,} 匹配前面的字符或子模式至少 n a{2,} 可以匹配 aaaaa
{n,m} 匹配前面的字符或子模式至少 n 次,最多 m a{1,3} 可以匹配 aaaaaa
*? 非贪心匹配,匹配前面的字符或子模式零次或多次,尽可能少地匹配 .*? 匹配尽可能少的任意字符
+? 非贪心匹配,匹配前面的字符或子模式一次或多次,尽可能少地匹配 .+? 匹配尽可能少的一个或多个字符
?? 非贪心匹配,匹配前面的字符或子模式零次或一次,尽可能少地匹配 a?? 匹配尽可能少的零个或一个 a
{n}? 非贪心匹配,匹配前面的字符或子模式恰好 n a{3}? 匹配 aaa,但会尝试更短的匹配
{n,}? 非贪心匹配,匹配前面的字符或子模式至少 n 次,尽可能少地匹配 a{2,}? 匹配至少两个 a,但尽可能少
{n,m}? 非贪心匹配,匹配前面的字符或子模式至少 n 次,最多 m 次,尽可能少地匹配 a{1,3}? 匹配 aaaaaa,但会优先尝试更短的匹配

(三)位置匹配

表达式 描述 示例及说明
^ 匹配字符串的开头 ^a 可以匹配以 a 开头的字符串
$$` 匹配字符串的结尾 a$$ 可以匹配以a` 结尾的字符串
\b 匹配单词边界 \bword\b 可以匹配独立的单词 word,但不会匹配 wording 中的 word
\B 匹配非单词边界 \Bword\B 可以匹配 wording 中的 word,但不会匹配独立的单词 word
^(多行模式) 在多行模式下,匹配每一行的开头 (?m)^a 可以匹配多行字符串中以 a 开头的每一行
$$`(多行模式) 在多行模式下,匹配每一行的结尾 (?m)a$$ 可以匹配多行字符串中以a` 结尾的每一行

(四)分组与引用

表达式 描述 示例及说明
() 分组,将多个字符或子模式组合在一起作为一个整体进行匹配和操作 (ab)+ 可以匹配 ababab
\1\2 引用前面的分组,\1 引用第一个分组,\2 引用第二个分组等 (\d+)\.\1 可以匹配 123.123456.456 等,其中 \1 引用了第一个分组 (\d+)
(?:...) 非捕获分组,将多个字符或子模式组合在一起,但不进行捕获 (?:ab)+ 可以匹配 ababab 等,但不会捕获分组内容
(?=...) 正向肯定预查,在匹配的当前位置,确保其后能匹配指定的模式,但不消耗字符 (?=\d+) 可以在当前位置后匹配任意数字,但不包括数字本身
(?!...) 正向否定预查,在匹配的当前位置,确保其后不能匹配指定的模式,不消耗字符 (?!abc) 可以在当前位置后确保不匹配 abc
(?<=...) 反向肯定预查,在匹配的当前位置,确保其前能匹配指定的模式,不消耗字符 (?<=abc) 可以在当前位置前匹配 abc,但不包括 abc 本身
(?<!...) 反向否定预查,在匹配的当前位置,确保其前不能匹配指定的模式,不消耗字符 (?<!abc) 可以在当前位置前确保不匹配 abc

三、常见应用场景

(一)验证数据格式

验证内容 正则表达式 示例及说明
邮件地址 ^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$ 匹配常见的电子邮件地址,如 user@example.com
手机号码(中国大陆) ^1[3-9]\d{9}$ 匹配中国大陆手机号码,如 13812345678
身份证号码 ^\d{15}(\d{2}[0-9xX])?$ 匹配 15 位或 18 位身份证号码,如 123456789012345678
URL `^(https? ftp)://\s/$.?#.\s*$` 匹配常见的 URL,如 http://example.comhttps://example.com/page
IPv4 地址 `^(25[0-5] 2[0-4]\d 1\d{2} [1-9]?\d).(25[0-5] 2[0-4]\d 1\d{2} [1-9]?\d).(25[0-5] 2[0-4]\d 1\d{2} [1-9]?\d).(25[0-5] 2[0-4]\d 1\d{2} [1-9]?\d)$` 匹配合法的 IPv4 地址,如 192.168.0.1
日期(YYYY-MM-DD) ^\d{4}-\d{2}-\d{2}$ 匹配日期格式,如 2024-10-01
货币金额 ^\d+(\.\d{2})?$ 匹配货币金额,如 123123.45
银行卡号 ^\d{16,19}$ 匹配常见的银行卡号,如 1234567890123456
社交安全号码(SSN) `^(?!000 666 9\d{2})\d{3}-(?!00)\d{2}-(?!0000)\d{4}$` 匹配美国 SSN 号码,如 123-45-6789
域名 ^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$ 匹配域名,如 example.comsub.domain.co.uk

(二)提取特定信息

提取内容 正则表达式 示例及说明
HTML 标签内容 <[^>]+>([^<]+)</[^>]+> 从 HTML 中提取标签内容,如 <p>Hello</p> 提取 Hello
URL 参数 [?&]([^=&]+)=([^&]*) 从 URL 中提取参数,如 ?page=1&size=10 提取 page=1size=10
日志文件中的时间戳 \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} 从日志文件中提取时间戳,如 2024-10-01 12:34:56
日志文件中的 IP 地址 \b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b 从日志文件中提取 IP 地址,如 192.168.0.1
文本中的电话号码 \d{3}-\d{3}-\d{4} 提取电话号码,如 123-456-7890
文本中的日期 \b\d{4}-\d{2}-\d{2}\b 提取日期,如 2024-10-01
文本中的邮箱地址 \b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b 提取邮箱地址,如 user@example.com
文本中的 URL \bhttps?://[^\s]+ 提取 URL,如 http://example.com
文本中的信用卡号 `\b(?:\d{4}-){3}\d{4} \b\d{16}\b` 提取信用卡号,如 1234-5678-9012-34561234567890123456
文本中的价格 \b\d+(\.\d{2})?\b 提取价格,如 123123.45

(三)替换文本内容

替换内容 正则表达式 示例及说明
多个空格替换为一个 s/\s+/ /g 将文本中的多个连续空格替换为一个空格,如 Hello World 替换为 Hello World
日期格式转换 s/(\d{4})-(\d{2})-(\d{2})/\3-\2-\1/g 将日期格式从 YYYY-MM-DD 替换为 DD-MM-YYYY,如 2024-10-01 替换为 01-10-2024
URL 参数排序 s/([&?])([^\s&]+)=([^\s&]+)([&])([^\s&]+)=([^\s&]+)/\1\5=\6\4\2=\3/g 对 URL 参数进行排序,如 ?b=2&a=1 替换为 ?a=1&b=2
HTML 标签转换 s/<[^>]+>//g 去除 HTML 标签,如 <p>Hello</p> 替换为 Hello
转义特殊字符 s/([<>&'"/])/\\\$1/g 转义 HTML 特殊字符,如 < 替换为 &lt;
标准化电话号码 s/(\d{3})-(\d{3})-(\d{4})/(\1) \2-\3/g 将电话号码格式标准化,如 123-456-7890 替换为 (123) 456-7890
转换为小写 s/[A-Z]/\l&/g 将文本转换为小写,如 Hello World 替换为 hello world
转换为大写 s/[a-z]/\u&/g 将文本转换为大写,如 hello world 替换为 HELLO WORLD
首字母大写 `s/(^ \s)([a-z])/\1\u\2/g` 将每个单词的首字母大写,如 hello world 替换为 Hello World

四、常用修饰符

修饰符 描述 示例及说明
i 忽略大小写 /abc/i 匹配 abcAbcABC
g 全局匹配,查找所有匹配而非在第一个匹配后停止 /abc/g 在字符串中查找所有 abc 匹配
m 多行模式,^ 和 $$` 匹配每一行的开头和结尾 (?m)^abc$$ 匹配多行字符串中每一行以abc` 开头和结尾的行
s 单行模式,. 匹配包括换行符在内的所有字符 (?s).+ 匹配包括换行符在内的所有字符
u Unicode 模式,支持 Unicode 字符 /abc/u 支持 Unicode 字符匹配
x 扩展模式,忽略模式中的空白字符和注释 (?x)\d+ # 匹配数字 匹配数字,忽略注释和空白

五、正则表达式工具推荐

(一)在线正则表达式测试工具

工具名称 网址 特点
Regex101 https://regex101.com/ 支持多种编程语言,提供详细的匹配结果和解释,支持在线调试和修改
正则表达式在线测试 https://tool.oschina.net/regex 国内工具,支持中文,界面简洁,操作方便
Debuggex https://debuggex.com/ 以可视化的方式展示正则表达式的匹配过程,帮助理解复杂的匹配逻辑
Regexr https://regexr.com/ 提供丰富的示例和教程,支持实时测试和调试,支持多种正则表达式引擎

(二)编程语言中的正则表达式库

编程语言 库名称 描述
Python re Python 的内置正则表达式库,功能强大,支持丰富的正则表达式操作
JavaScript RegExp JavaScript 的内置正则表达式对象,广泛用于前端和 Node.js 开发
Java java.util.regex Java 的正则表达式库,功能全面,支持复杂的正则表达式操作
PHP preg PHP 的 PCRE(Perl 兼容正则表达式)库,功能强大,广泛用于 Web 开发
C# System.Text.RegularExpressions .NET 的正则表达式库,功能丰富,支持多种正则表达式操作
Ruby Regexp Ruby 的内置正则表达式库,语法简洁,易于使用

六、正则表达式在不同编程语言中的使用示例

(一)Python

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import re

# 匹配验证
pattern = r'^\d{3}-\d{3}-\d{4}$'
text = '123-456-7890'
match = re.match(pattern, text)
if match:
print('匹配成功')
else:
print('匹配失败')

# 搜索表
text = 'Hello 123 World 456'
new_text = re.sub(r'\d+', 'NUM', text)
print(new_text) # 输出: Hello NUM World NUM

# 提取信息
text = 'Email: user@example.com, Phone: 123-456-7890'
emails = re.findall(r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b', text)
phones = re.findall(r'\d{3}-\d{3}-\d{4}', text)
print(emails) # 输出: ['user@example.com']
print(phones) # 输出: ['123-456-7890']

(二)JavaScript

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 匹配验证
const pattern = /^\d{3}-\d{3}-\d{4}$/;
const text = '123-456-7890';
if (pattern.test(text)) {
console.log('匹配成功');
} else {
console.log('匹配失败');
}

// 搜索网页
const text = 'Hello 123 World 456';
const new_text = text.replace(/\d+/g, 'NUM');
console.log(new_text); // 输出: Hello NUM World NUM

// 提取信息
const text = 'Email: user@example.com, Phone: 123-456-7890';
const emails = text.match(/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/g);
const phones = text.match(/\d{3}-\d{3}-\d{4}/g);
console.log(emails); // 输出: ['user@example.com']
console.log(phones); // 输出: ['123-456-7890']

(三)Java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import java.util.regex.*;

public class RegexExample {
public static void main(String[] args) {
// 匹配验证
String pattern = "^\\d{3}-\\d{3}-\\d{4}$";
String text = "123-456-7890";
boolean matches = Pattern.matches(pattern, text);
System.out.println(matches ? "匹配成功" : "匹配失败"); // 输出: 匹配成功

// 替换文本
String text = "Hello 123 World 456";
String new_text = text.replaceAll("\\d+", "NUM");
System.out.println(new_text); // 输出: Hello NUM World NUM

// 提取信息
String text = "Email: user@example.com, Phone: 123-456-7890";
Pattern emailPattern = Pattern.compile("\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}\\b");
Matcher emailMatcher = emailPattern.matcher(text);
while (emailMatcher.find()) {
System.out.println(emailMatcher.group()); // 输出: user@example.com
}

Pattern phonePattern = Pattern.compile("\\d{3}-\\d{3}-\\d{4}");
Matcher phoneMatcher = phonePattern.matcher(text);
while (phoneMatcher.find()) {
System.out.println(phoneMatcher.group()); // 输出: 123-456-7890
}
}
}

七、注意事项

(一)性能问题

  • 避免过度使用正则表达式:正则表达式虽然强大,但过度使用会导致代码可读性下降和性能问题。对于简单的字符串操作,优先考虑使用字符串方法(如 splitreplace 等)。
  • 优化复杂的正则表达式:避免使用过于复杂的模式,尽量使用非捕获分组 ?: 和非贪心匹配来提高性能。
  • 使用预编译:在需要多次使用同一个正则表达式时,提前编译正则表达式可以提高性能,如 Java 中的 Pattern.compile 和 Python 中的 re.compile

(二)特殊字符转义

  • 反斜杠转义:在正则表达式中,一些特殊字符(如 .*+?()[]{}^$\ 等)具有特殊含义,如果需要匹配这些字符本身,需要使用反斜杠 \ 进行转义。例如,要匹配 .,应使用 \.
  • 编程语言中的转义:在某些编程语言中(如 Python、Java 等),反斜杠本身需要转义,因此需要使用双反斜杠 \\。例如,在 Python 中匹配 \d 需要写成 \\d

(三)贪心与非贪心匹配

  • 贪心匹配:默认情况下,正则表达式中的数量匹配符号(如 *+?{n,m} 等)是贪心的,会尽可能多地匹配字符。例如,<.*> 会匹配 <html>...</html> 中的整个字符串。
  • 非贪心匹配:如果需要非贪心匹配,可以在数量匹配符号后添加 ?。例如,<.*?> 会匹配 <html><body> 等尽可能少的字符。

(四)常见问题与解决方法

  • 匹配换行符:默认情况下,. 不匹配换行符 \n。如果需要匹配包括换行符在内的所有字符,可以使用单行模式 s 修饰符。例如,(?s).+ 会匹配包括换行符在内的所有字符。
  • 多行模式匹配:在多行字符串中,如果需要匹配每一行的开头或结尾,可以使用多行模式 m 修饰符。例如,(?m)^abc$ 会匹配多行字符串中每一行以 abc 开头和结尾的行。
  • 处理 Unicode 字符:在处理 Unicode 字符时,确保使用支持 Unicode 的正则表达式库,并添加 u 修饰符。例如,在 JavaScript 中使用 /abc/u 来匹配 Unicode 字符。

八、正则表达式学习资源

(一)书籍

书名 作者 描述
《正则表达式权威指南》 杰夫·弗里德劳 全面深入地介绍了正则表达式的原理、语法和应用,适合初学者和进阶读者
《精通正则表达式》 杰夫·弗里德劳 详细讲解了正则表达式的高级技巧和优化方法,适合有一定基础的读者
《正则表达式 Pocket 参考》 杰夫·弗里德劳 精简实用的正则表达式参考手册,适合随时查阅

(二)在线教程

网站名称 网址 特点
MDN Web Docs https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions 详细的正则表达式教程,涵盖语法、示例和常见应用,适合 JavaScript 开发者
Runoob https://www.runoob.com/regexp/regexp-tutorial.html 简洁易懂的正则表达式教程,包含丰富的示例和练习,适合初学者
W3School https://www.w3schools.com/js/js_regexp.asp 提供正则表达式的基础教程和示例,适合快速入门

(三)视频教程

平台名称 视频名称 特点
Bilibili 正则表达式从入门到精通 详细的正则表达式讲解,包含大量实例和练习,适合初学者和进阶读者
YouTube Regular Expressions Tutorial for Beginners 由 freeCodeCamp 提供的正则表达式入门教程,内容清晰,适合初学者
Udemy The Complete Regular Expressions Course 全面的正则表达式课程,涵盖基础和高级内容,提供实践项目和练习

九、总结

正则表达式是一种强大的文本处理工具,广泛应用于数据验证、信息提取、文本替换等领域。掌握正则表达式的基本语法和应用场景,可以帮助开发者更高效地处理文本数据。通过不断学习和实践,可以逐渐掌握正则表达式的高级技巧,解决复杂的文本处理问题。

在学习和使用正则表达式时,需要注意性能优化、特殊字符转义、贪心与非贪心匹配等问题。利用在线工具和学习资源,可以更轻松地理解和掌握正则表达式的使用方法。