一、正则表达式简介
1. 什么是正则表达式?
正则表达式(Regular Expression,简称regex或regexp)是一种用于描述搜索模式的特殊字符序列。它可以用于查找、替换或验证文本中的特定模式。正则表达式广泛应用于字符串匹配和文本处理领域,如数据验证、信息抽取和文本编辑等。
2. 常见应用场景
正则表达式在日常编程中有着广泛的应用,例如:
- 验证用户输入(如邮箱地址、电话号码)
- 数据清洗和格式化
- 从日志文件中提取有用信息
- 搜索和替换文本
二、正则表达式的基础构成
1. 普通字符
普通字符是指没有特殊含义的字符,它们在正则表达式中直接表示自身。例如:
a
匹配字符'a'
1
匹配字符'1'
.
匹配字符'.'
2. 元字符
元字符是有特殊意义的字符,用于构建复杂的模式。常见的元字符包括:
.
:匹配除换行符以外的任意单个字符。^
:匹配字符串的开始位置。$
:匹配字符串的结束位置。*
:匹配前面的元素零次或多次。+
:匹配前面的元素一次或多次。?
:匹配前面的元素零次或一次。|
:表示“或”,匹配左右两边的任意一个表达式。()
:用于分组,组合多个表达式。[]
:表示字符类,匹配方括号中的任意一个字符。
3. 字符类
字符类是用来定义一个字符集合,用方括号括起来。字符类中的每个字符都可以被匹配。常见的字符类有:
[abc]
:匹配'a'
、'b'
或'c'
中的任意一个字符。[0-9]
:匹配'0'
到'9'
之间的任意一个数字。[^abc]
:匹配除'a'
、'b'
、'c'
之外的任意字符。
4. 量词
量词用于指定前面的元素可以重复的次数。常见的量词包括:
*
:匹配前面的元素零次或多次。+
:匹配前面的元素一次或多次。?
:匹配前面的元素零次或一次。{n}
:匹配前面的元素恰好n
次。{n,}
:匹配前面的元素至少n
次。{n,m}
:匹配前面的元素至少n
次,至多m
次。
5. 边界匹配
边界匹配符用于指定匹配的开始或结束位置:
^
:匹配字符串的开头。$
:匹配字符串的结尾。\b
:匹配单词边界。\B
:匹配非单词边界。
6. 分组和捕获
分组是将正则表达式的多个部分组合起来,使它们作为一个整体进行匹配。分组使用小括号 ()
来表示。
(abc)
:将'abc'
作为一个整体进行匹配。(\d{3})
:将三位数字作为一个整体进行匹配。
分组还可以用于捕获匹配的内容,捕获的内容可以在后续使用。
7. 转义字符
由于某些字符在正则表达式中具有特殊含义,如果要匹配这些字符本身,需要使用反斜杠 \
进行转义。例如:
\.
:匹配.
字符,而不是作为任意字符的通配符。\*
:匹配*
字符,而不是作为量词。
三、正则表达式的高级特性
1. 非捕获组
在使用捕获组 ()
时,正则表达式会保存匹配的内容,有时这并不是我们想要的。如果你只想分组但不捕获,可以使用非捕获组 (?:...)
:
(?:abc)
:匹配abc
,但不会捕获该内容。
2. 回溯引用
回溯引用允许你在正则表达式中引用之前捕获的内容。可以通过反斜杠 \
和数字来使用回溯引用:
(abc)\1
:匹配abcabc
,\1
引用第一个捕获组的内容。(.)\1
:匹配两个连续的相同字符,如aa
、bb
。
3. 正向先行断言 (Lookahead)
正向先行断言用于检查某个子字符串是否在另一个字符串的前面,但不包括在最终的匹配中。用法是 (?=...)
:
\d(?=px)
:匹配跟在px
前面的数字,但不包含px
。\w+(?=\s)
:匹配后面跟着空白字符的单词,但不包括空白字符。
4. 负向先行断言 (Negative Lookahead)
负向先行断言用于确保某个子字符串不出现在另一个字符串的前面。用法是 (?!...)
:
\d(?!px)
:匹配跟在非px
前面的数字。\w+(?!s)
:匹配后面不跟空白字符的单词。
5. 正向后发断言 (Lookbehind)
正向后发断言用于检查某个子字符串是否在另一个字符串的后面,但不包括在最终的匹配中。用法是 (?<=...)
:
(?<=\$)\d+
:匹配跟在美元符号$
后面的数字,但不包括$
。(?<=\bword\s)\w+
:匹配跟在单词word
后面的单词,但不包括word
。
6. 负向后发断言 (Negative Lookbehind)
负向后发断言用于确保某个子字符串不出现在另一个字符串的后面。用法是 (?<!...)
:
(?<!\$)\d+
:匹配不跟在美元符号$
后面的数字。(?<!\bword\s)\w+
:匹配不跟在单词word
后面的单词。
7. 贪婪与懒惰匹配
默认情况下,量词是贪婪的,会匹配尽可能多的字符。可以通过在量词后加 ?
使其变为懒惰模式,即尽可能少地匹配。
.*
:贪婪匹配,匹配尽可能多的字符。.*?
:懒惰匹配,匹配尽可能少的字符。
8. 嵌入条件 (Conditionals)
某些正则表达式引擎支持条件匹配。语法是 (?(条件)真分支|假分支)
:
(?(1)abc|def)
:如果第一个捕获组匹配成功,则匹配abc
,否则匹配def
。
9. 递归匹配
递归匹配用于匹配嵌套的模式,如匹配平衡的括号。并非所有正则表达式引擎都支持此功能,语法因引擎而异:
(\((?:[^()]|(?R))*\))
:在支持递归的引擎中,用于匹配平衡的括号。
10. 注释
在某些正则表达式引擎中,可以通过 (?x)
启用忽略空白和注释模式,从而使正则表达式更具可读性:
(?x) \d+ \s* # 匹配一个或多个数字,然后是零个或多个空白
。
11. 命名捕获组
命名捕获组允许你为捕获的子字符串命名,以便在后续处理中更方便地引用。语法为 (?<name>...)
:
(?<area_code>\d{3})
:匹配三位数字,并将其命名为area_code
。
12. 条件判断 (Conditional Expressions)
在一些高级正则表达式引擎中,允许使用条件表达式来选择不同的模式进行匹配。语法为 (?(id/name)yes-pattern|no-pattern)
:
(?(1)abc|def)
:如果捕获组 1 存在,则匹配abc
,否则匹配def
。
四、常见正则表达式
1. 邮箱地址验证:
^[\w\.-]+@[a-zA-Z\d\.-]+\.[a-zA-Z]{2,6}$
2. 手机号码验证(中国):
^1[3-9]\d{9}$
3. IP地址验证(IPv4):
^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$
4. 邮政编码验证(中国):
^\d{6}$
5. 日期格式验证(YYYY-MM-DD):
^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$
6. URL验证:
^https?:\/\/[^\s/$.?#].[^\s]*$
7. 密码强度验证(至少8位,包括字母、数字、特殊字符):
^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$
8. HTML标签匹配:
<(\/?[\w\s]*)(\s*[^>]*)>
9. 匹配含有至少一个数字的字符串:
\d+
10. 去除字符串首尾空白:
^\s+|\s+$