正则表达式总结
一、正则表达式简介
正则表达式(Regular Expression)是一种用于匹配字符串中字符组合的模式,广泛应用于文本处理、数据验证、搜索替换等领域。通过特定的字符和符号组合来定义匹配规则,能够高效地对字符串进行复杂的匹配和操作。
正则表达式引擎会从左到右扫描目标字符串,试图找到与正则表达式模式匹配的文本片段。当找到匹配时,会返回匹配的文本内容或根据指定的操作(如替换)进行处理。
二、基本语法
(一)字符匹配
表达式 |
描述 |
示例及说明 |
. |
匹配任意单个字符(除换行符\n 外) |
a.b 可以匹配 a1b 、a2b 、a b 等 |
[abc] |
匹配方括号内的任意一个字符 |
[abc] 可以匹配 a 、b 或 c |
[a-z] |
匹配指定范围内的任意一个字符 |
[a-z] 可以匹配任意一个小写字母 |
[^abc] |
匹配不在方括号内的任意一个字符 |
[^abc] 可以匹配除 a 、b 、c 之外的任意字符 |
\d |
匹配任意数字,等价于 [0-9] |
\d 可以匹配 0 、1 、9 等 |
\w |
匹配任意字母或数字或下划线,等价于 [A-Za-z0-9_] |
\w 可以匹配 a 、B 、7 、_ |
\s |
匹配任意空白字符,包括空格、制表符、换页符等 |
\s 可以匹配空格、\t 、\f 等 |
\D |
匹配任意非数字,等价于 [^0-9] |
\D 可以匹配 a 、@ 、# 等 |
\W |
匹配任意非字母数字下划线,等价于 [^A-Za-z0-9_] |
\W 可以匹配 @ 、# 、% 等 |
\S |
匹配任意非空白字符 |
\S 可以匹配 a 、7 、@ 等 |
(二)数量匹配
表达式 |
描述 |
示例及说明 |
* |
匹配前面的字符或子模式零次或多次 |
a* 可以匹配 "" (空字符串)、a 、aa 等 |
+ |
匹配前面的字符或子模式一次或多次 |
a+ 可以匹配 a 、aa 等,但不能匹配空字符串 |
? |
匹配前面的字符或子模式零次或一次 |
a? 可以匹配 "" (空字符串)或 a |
{n} |
匹配前面的字符或子模式恰好 n 次 |
a{3} 可以匹配 aaa |
{n,} |
匹配前面的字符或子模式至少 n 次 |
a{2,} 可以匹配 aa 、aaa 等 |
{n,m} |
匹配前面的字符或子模式至少 n 次,最多 m 次 |
a{1,3} 可以匹配 a 、aa 、aaa |
*? |
非贪心匹配,匹配前面的字符或子模式零次或多次,尽可能少地匹配 |
.*? 匹配尽可能少的任意字符 |
+? |
非贪心匹配,匹配前面的字符或子模式一次或多次,尽可能少地匹配 |
.+? 匹配尽可能少的一个或多个字符 |
?? |
非贪心匹配,匹配前面的字符或子模式零次或一次,尽可能少地匹配 |
a?? 匹配尽可能少的零个或一个 a |
{n}? |
非贪心匹配,匹配前面的字符或子模式恰好 n 次 |
a{3}? 匹配 aaa ,但会尝试更短的匹配 |
{n,}? |
非贪心匹配,匹配前面的字符或子模式至少 n 次,尽可能少地匹配 |
a{2,}? 匹配至少两个 a ,但尽可能少 |
{n,m}? |
非贪心匹配,匹配前面的字符或子模式至少 n 次,最多 m 次,尽可能少地匹配 |
a{1,3}? 匹配 a 、aa 、aaa ,但会优先尝试更短的匹配 |
(三)位置匹配
表达式 |
描述 |
示例及说明 |
^ |
匹配字符串的开头 |
^a 可以匹配以 a 开头的字符串 |
$$` |
匹配字符串的结尾 |
a$$ 可以匹配以 a` 结尾的字符串 |
\b |
匹配单词边界 |
\bword\b 可以匹配独立的单词 word ,但不会匹配 wording 中的 word |
\B |
匹配非单词边界 |
\Bword\B 可以匹配 wording 中的 word ,但不会匹配独立的单词 word |
^ (多行模式) |
在多行模式下,匹配每一行的开头 |
(?m)^a 可以匹配多行字符串中以 a 开头的每一行 |
$$`(多行模式) |
在多行模式下,匹配每一行的结尾 |
(?m)a$$ 可以匹配多行字符串中以 a` 结尾的每一行 |
(四)分组与引用
表达式 |
描述 |
示例及说明 |
() |
分组,将多个字符或子模式组合在一起作为一个整体进行匹配和操作 |
(ab)+ 可以匹配 ab 、abab 等 |
\1 、\2 |
引用前面的分组,\1 引用第一个分组,\2 引用第二个分组等 |
(\d+)\.\1 可以匹配 123.123 、456.456 等,其中 \1 引用了第一个分组 (\d+) |
(?:...) |
非捕获分组,将多个字符或子模式组合在一起,但不进行捕获 |
(?:ab)+ 可以匹配 ab 、abab 等,但不会捕获分组内容 |
(?=...) |
正向肯定预查,在匹配的当前位置,确保其后能匹配指定的模式,但不消耗字符 |
(?=\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.com 、https://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})?$ |
匹配货币金额,如 123 、123.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.com 、sub.domain.co.uk |
(二)提取特定信息
提取内容 |
正则表达式 |
示例及说明 |
HTML 标签内容 |
<[^>]+>([^<]+)</[^>]+> |
从 HTML 中提取标签内容,如 <p>Hello</p> 提取 Hello |
URL 参数 |
[?&]([^=&]+)=([^&]*) |
从 URL 中提取参数,如 ?page=1&size=10 提取 page=1 和 size=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-3456 或 1234567890123456 |
文本中的价格 |
\b\d+(\.\d{2})?\b |
提取价格,如 123 或 123.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 特殊字符,如 < 替换为 < |
标准化电话号码 |
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 匹配 abc 、Abc 、ABC 等 |
g |
全局匹配,查找所有匹配而非在第一个匹配后停止 |
/abc/g 在字符串中查找所有 abc 匹配 |
m |
多行模式,^ 和 $$` 匹配每一行的开头和结尾 |
(?m)^abc$$ 匹配多行字符串中每一行以 abc` 开头和结尾的行 |
s |
单行模式,. 匹配包括换行符在内的所有字符 |
(?s).+ 匹配包括换行符在内的所有字符 |
u |
Unicode 模式,支持 Unicode 字符 |
/abc/u 支持 Unicode 字符匹配 |
x |
扩展模式,忽略模式中的空白字符和注释 |
(?x)\d+ # 匹配数字 匹配数字,忽略注释和空白 |
五、正则表达式工具推荐
(一)在线正则表达式测试工具
(二)编程语言中的正则表达式库
编程语言 |
库名称 |
描述 |
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)
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) print(phones)
|
(二)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);
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); console.log(phones);
|
(三)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);
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()); }
Pattern phonePattern = Pattern.compile("\\d{3}-\\d{3}-\\d{4}"); Matcher phoneMatcher = phonePattern.matcher(text); while (phoneMatcher.find()) { System.out.println(phoneMatcher.group()); } } }
|
七、注意事项
(一)性能问题
- 避免过度使用正则表达式:正则表达式虽然强大,但过度使用会导致代码可读性下降和性能问题。对于简单的字符串操作,优先考虑使用字符串方法(如
split
、replace
等)。
- 优化复杂的正则表达式:避免使用过于复杂的模式,尽量使用非捕获分组
?:
和非贪心匹配来提高性能。
- 使用预编译:在需要多次使用同一个正则表达式时,提前编译正则表达式可以提高性能,如 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 参考》 |
杰夫·弗里德劳 |
精简实用的正则表达式参考手册,适合随时查阅 |
(二)在线教程
(三)视频教程
九、总结
正则表达式是一种强大的文本处理工具,广泛应用于数据验证、信息提取、文本替换等领域。掌握正则表达式的基本语法和应用场景,可以帮助开发者更高效地处理文本数据。通过不断学习和实践,可以逐渐掌握正则表达式的高级技巧,解决复杂的文本处理问题。
在学习和使用正则表达式时,需要注意性能优化、特殊字符转义、贪心与非贪心匹配等问题。利用在线工具和学习资源,可以更轻松地理解和掌握正则表达式的使用方法。