正则表达式(Regular Expressions)
正则表达式(Regular Expressions, 简称 Regex)是一种用于字符串匹配和处理的强大工具,通过特定的模式(Pattern)描述字符串。它在验证、替换、分割、提取等操作中非常有效。以下是一些基本概念和常见使用场景:
- 由于正则表达式的语法复杂,容易出现错误匹配,因此在实际使用前最好先测试验证。
- 解决方法:利用正则调试工具(如 regex101 或 RegExr)在构建和测试正则表达式。
基本概念
- 字符类:使用方括号
[]
定义匹配的字符范围,例如[0-9]
匹配任意数字。 - 预定义字符:
\d
:匹配数字[0-9]
\w
:匹配字母、数字或下划线[A-Za-z0-9_]
\s
:匹配空白字符(空格、制表符等)
- 量词:指定匹配次数。
*
:匹配前一个字符 0 次或多次+
:匹配前一个字符 1 次或多次?
:匹配前一个字符 0 次或 1 次{n}
:匹配前一个字符恰好 n 次{n, m}
:匹配前一个字符 n 至 m 次
- 定位符:用于指定匹配位置。
^
:匹配字符串的开头$
:匹配字符串的结尾
- 分组与引用:
()
:用于分组|
:表示“或”操作\1
、\2
等:用于引用之前的分组
常见应用场景
- 验证输入格式:正则可用于校验字符串的格式,如验证电子邮件、手机号、邮政编码等。例如,
^\w+@[a-zA-Z_]+?\.[a-zA-Z]{2,3}$
可用来验证邮箱格式。 - 搜索和替换:可根据正则模式查找匹配内容并替换。例如,在字符串中替换所有空格可以使用
\s+
。 - 提取信息:常用于从文本中提取特定数据(如 URL、日期、时间等)。例如,匹配日期
\d{4}-\d{2}-\d{2}
可以用来提取格式为yyyy-mm-dd
的日期。
以下是常用正则表达式符号和校验规则的表格介绍,方便查阅和快速了解正则表达式的作用及其常见用途:
正则符号 | 作用 | 示例 | 解释 |
---|---|---|---|
. | 匹配任意单个字符 | a.c | 匹配 “abc”、“adc” 等 |
^ | 匹配字符串的开头 | ^Hello | 匹配以 “Hello” 开头的字符串 |
$ | 匹配字符串的结尾 | world$ | 匹配以 “world” 结尾的字符串 |
* | 匹配前一个字符 0 次或多次 | a* | 匹配 0 个或多个 “a” |
+ | 匹配前一个字符 1 次或多次 | a+ | 匹配 1 个或多个 “a” |
? | 匹配前一个字符 0 次或 1 次 | a? | 匹配 0 个或 1 个 “a” |
{n} | 匹配前一个字符恰好 n 次 | a{3} | 匹配 3 个连续的 “a” |
{n, m} | 匹配前一个字符 n 到 m 次 | a{1,3} | 匹配 1 到 3 个 “a” |
[] | 匹配字符集中的任意一个字符 | [abc] | 匹配 “a”、“b” 或 “c” |
[^] | 匹配不在字符集中的字符 | [^abc] | 匹配除 “a”、“b”、“c” 外的字符 |
\d | 匹配数字 [0-9] | \d{3} | 匹配任意 3 位数字 |
\w | 匹配字母、数字或下划线 | \w+ | 匹配任意长度的单词 |
\s | 匹配空白字符 | \s+ | 匹配 1 个或多个空白字符 |
` | ` | 或运算符 | `a |
() | 分组 | (ab)+ | 匹配 “ab” 一次或多次 |
\b | 单词边界 | \bword\b | 匹配整个单词 “word” |
常用校验规则
校验项 | 正则表达式 | 解释 |
---|---|---|
手机号(大陆) | ^1[3-9]\d{9}$ | 匹配以 “1” 开头的 11 位大陆手机号 |
邮箱地址 | ^\w+@[a-zA-Z_]+?\.[a-zA-Z]{2,3}$ | 匹配邮箱格式(如 example@domain.com ) |
身份证号(中国) | `^\d{15} | \d{18}$` |
邮政编码(中国) | ^[1-9]\d{5}$ | 匹配 6 位的中国邮政编码 |
URL | ^https?://[^\s/$.?#].[^\s]*$ | 匹配 URL,支持 http 和 https |
IPv4 地址 | `^(25[0-5] | 2[0-4]\d |
日期(yyyy-mm-dd) | ^\d{4}-\d{2}-\d{2}$ | 匹配 “2024-10-31” 格式的日期 |
车牌号(中国) | ^[京津沪渝辽川鄂…]\w{5}$ | 匹配中国车牌号 |
简单密码(6-12 位) | ^[\w!@#$%^&*]{6,12}$ | 匹配 6 到 12 位的简单密码 |
1. 避免贪婪匹配
- 默认情况下,
*
、+
、?
等量词是贪婪的,会匹配尽可能多的字符。例如,<.*>
会匹配字符串中的第一个<
到最后一个>
。 - 解决方法:可以在量词后加
?
,如<.*?>
,表示非贪婪模式,匹配最少的字符。
2. 正则表达式的性能
- 复杂的正则表达式在长字符串上可能会降低性能,甚至引发回溯导致的性能瓶颈。例如大量分组、重复匹配等会造成正则的效率下降。
- 解决方法:尽量优化正则结构,避免使用过多的嵌套和不必要的分组。若可能,考虑其他方案处理。
3. 字符转义
- 正则中很多符号有特殊含义(如
.
、*
、?
、+
、[]
等),直接使用这些符号可能导致错误匹配。 - 解决方法:如需匹配这些特殊字符,前面加上
\
转义,例如\.
可以匹配一个句点字符。
4. 正确处理 Unicode 和多字节字符
- 在处理中文、日文、韩文(CJK 字符)和 emoji 等 Unicode 字符时,普通的
\w
、\d
等可能无法正常匹配。 - 解决方法:使用 Unicode 支持的正则语法(如 JavaScript 中的
\p{}
或u
标志)。例如/\p{Script=Han}/u
用于匹配中文字符。
5. 验证输入格式和正则安全
- 用户输入的正则表达式可能会导致安全问题,尤其在允许用户自定义输入时,可能会形成“正则注入”。
- 解决方法:严格限制正则表达式的输入,或考虑其他方法避免将用户输入直接用于正则匹配。
6. 使用锚点避免全局匹配错误
^
和$
用于匹配字符串的开头和结尾,适当使用这些锚点可以提高匹配精度。例如,匹配整串手机号应使用^1[3-9]\d{9}$
,而不是仅使用1[3-9]\d{9}
。- 解决方法:根据需求选择合适的锚点,避免意外的部分匹配。
7. 正则表达式的可读性
- 复杂的正则表达式可读性差,维护困难,尤其是多行嵌套的正则表达式,容易产生错误。
- 解决方法:将正则拆分为多个部分,并适当添加注释。可以在编程语言中使用“正则构建器”工具或将复杂正则拆分成多个简单表达式。
8. 避免不必要的分组
()
会产生分组,便于捕获匹配的内容;但过多分组会影响效率,也可能导致意外的捕获。- 解决方法:若不需要捕获内容,可使用非捕获分组
(?:...)
,它不会影响捕获组的顺序。
9. 使用合适的标志
- 标志(flags)如
g
、i
、m
在不同环境中会影响匹配行为。g
:全局匹配i
:忽略大小写m
:多行匹配
- 解决方法:根据需求添加合适的标志,不使用时最好省略,以免引入不必要的复杂性。