一、正则表达式介绍
一个正则表达式是一种从左到右匹配主体字符串的模式。
“Regular expression”这个词比较拗口,我们常使用缩写的术语“regex”或“regexp”。
正则表达式可以从一个基础字符串中根据一定的匹配模式替换文本中的字符串、验证表单、提取字符串等等。
二、基本语法
2.1 匹配符号
| 符号 | 说明 |
|---|---|
| \b | 匹配边界,即字与空格间的位置。(\b所在位置的左右两个字符有一个是\W,即不是A-Z,a-z,0-9,_) |
| \B | 非单词边界匹配。 |
| \d | 匹配0-9中任意一个数字字符 |
| \D | 匹配除0-9外的非数字字符,等同于[^\d]
|
| \f | 匹配一个换页符 |
| \n | 匹配一个换行符 |
| \p | 匹配 CR/LF(等同于 \r\n),用来匹配 DOS 行终止符 |
| \r | 匹配一个回车符 |
| \s | 匹配空格、制表符、换行符等空白字符 |
| \S | 匹配非空白字符 |
| \t | 匹配一个制表符 |
| \v | 匹配一个垂直制表符 |
| \w | 匹配A-Z,a-z,0-9和_中任意一个 |
| \W | 非单词字符,等同于: [^\w]
|
| . | 匹配一个任意的字符,不匹配换行符。如 .* 匹配任意字符串 |
| \p{L} | 表示Unicode字母 |
| \p{N} | 表示Unicode数字 |
2.2 特殊含义符号
| 符号 | 说明 |
|---|---|
| \ | 转义,用于指定 { } [ ] / \ + * . $ ^|?这些特殊字符。如果想要匹配这些特殊字符则要在其前面加上反斜线 \。 |
| ^ | 表示一行的开头,而在[]内表示取反 |
| $ | 匹配一行的结束,如 R$ 表示以R结尾的行 |
| [] | 表示匹配某个范围内的字符,正则表达式特殊字符被放到中括号中,失去特殊含义,除了"^"和"-" 。如[a-z]表示匹配一个小写字母;[^a-z]表示匹配一个非小写字母。 |
| () | 作为一个整体进行匹配,如(ab)+表示匹配ab一次或多次,如 (cat|dog)+ 表达匹配一次或多次cat或dog |
| | | 或运算符就表示或,用作判断条件。 |
2.3 量词
通过量词可以设置一个内容出现的次数 ,量词只对它前边的一个内容起作。
| 符号 | 说明 |
|---|---|
| {3} | 匹配三个 |
| {3,6} | 匹配3到6个(默认贪婪模式,往多的匹配) |
| {3,6}? | 匹配3到6个,?表示非贪婪模式,即匹配最少个数。 |
| ? | 匹配前面元字符0次或1次,相当于{0,1};也会被用来表示懒惰匹配,如<.+?>可以匹配html标签 |
| + | 一个或多个,相当于{1,} |
| * | 匹配任意个(贪心匹配),相当于{0,} |
2.4 零宽断言
先行断言和后发断言都属于非捕获簇(不捕获文本 ,也不针对组合计进行计数)。
先行断言用于判断所匹配的格式是否在另一个确定的格式之前,匹配结果不包含该确定格式(仅作为约束)。
例如,我们想要获得所有跟在 $ 符号后的数字,我们可以使用正后发断言 (?<=\$)[0-9\.]*。
这个表达式匹配 $ 开头,之后跟着 0,1,2,3,4,5,6,7,8,9,. 这些字符可以出现大于等于 0 次。
零宽度断言如下:
| 符号 | 描述 |
|---|---|
| ?= | 正先行断言-存在 |
| ?! | 负先行断言-排除 |
| ?<= | 正后发断言-存在 |
| ?<! | 负后发断言-排除 |
2.4.1 ?=... 正先行断言
?=... 正先行断言,表示第一部分表达式之后必须跟着 ?=...定义的表达式。
返回结果只包含满足匹配条件的第一部分表达式。
定义一个正先行断言要使用 (?=...)。
如果将正先行断言式放在匹配式的后面,则表示匹配式后需要满足正先行断言式。
如果将正先行断言式放在匹配式的前面,则表示使用正先行断言式对匹配到的结果进行筛选。
例:
现在有文本如下
The fat cat sat on the mat.
使用正先行断言(T|t)he(?=\sfat)进行正则匹配,即 The 和 the 后面紧跟着 (空格)fat。也可以使用表达式(?=The\sfat)The进行匹配。
最终得到匹配的文本如下
The
例:
至少一个大写字母和一个小写字母,可以使用表达式 (?=.*?[a-z])(?=.*?[A-Z]).+
2.4.2 ?!... 负先行断言
负先行断言 ?! 用于筛选所有匹配结果,筛选条件为 其后不跟随着断言中定义的格式。
正先行断言 定义和 负先行断言 一样,区别就是 = 替换成 ! 也就是 (?!...)。
例:
有文本如下
The fat cat sat on the mat.
使用负先行断言(T|t)he(?!\sfat)进行正则匹配,即 The 和 the 后面没有 (空格)fat文本。
最终得到匹配的文本如下
the
2.4.3 ?<= ... 正后发断言
正后发断言 记作(?<=...) 用于筛选所有匹配结果,筛选条件为 其前跟随着断言中定义的格式。
如果将正后发断言式放在匹配式的前面,则表示匹配式前需要满足正后发断言式。
如果将正后发断言式放在匹配式的后面,则表示使用正后发断言式对匹配到的结果进行筛选。
例:
表达式 `` 匹配 fat 和 mat,且其前跟着 The 或 the。
有文本如下
The fat cat sat on the mat.
使用正后发断言(?<=The\s)(fat|mat)进行正则匹配,即 fat 或 mat前跟随着 The文本。也可以使用匹配式(fat|mat)(?<=The\sfat)进行匹配。
最终得到匹配的文本如下
fat
例:
匹配文本
我喜欢你
使用匹配式(?<=我)喜欢(?=你)
2.4.4 ?<!... 负后发断言
负后发断言 记作 (?<!...) 用于筛选所有匹配结果,筛选条件为 其前不跟随着断言中定义的格式。
例:
有文本如下
The fat cat sat on the mat.
使用正后发断言(?<!The\s)(fat|mat)进行正则匹配,即 fat 或 mat前不跟随着 The文本。
最终得到匹配的文本如下
mat
2.5 标志
标志也叫模式修正符,因为它可以用来修改表达式的搜索结果。
这些标志可以任意的组合使用,它也是整个正则表达式的一部分。
| 标志 | 描述 |
|---|---|
| i | 忽略大小写。 |
| g | 全局搜索。 |
| m | 多行修饰符:锚点元字符 ^ $ 工作范围在每行的起始。 |
| s | dotall |
| u | Unicode |
| y | 粘性(stucky) |
2.5.1 全局搜索 (Global search)
修饰符 g 常用于执行一个全局搜索匹配,即(不仅仅返回第一个匹配的,而是返回全部)。
例:
表达式 /.(at)/g 表示搜索 任意字符(除了换行)+ at,并返回全部结果。
2.5.2 忽略大小写 (Case Insensitive)
修饰语 i 用于忽略大小写。
例:
如,表达式 /The/gi 表示在全局搜索 The,在后面的 i 将其条件修改为忽略大小写,则变成搜索 the 和 The。
2.5.3 多行修饰符 (Multiline)
多行修饰符 m 常用于执行一个多行匹配。
像之前介绍的 ^和$ 用于检查格式是否是在待检测字符串的开头或结尾。但我们如果想要它在每行的开头和结尾生效,我们需要用到多行修饰符 m。
例如,表达式 /at(.)?$/gm 表示小写字符 a 后跟小写字符 t ,末尾可选除换行符外任意字符。根据 m 修饰符,现在表达式匹配每行的结尾。
2.6 捕获组
2.6.1 捕获分组
在正则表达式中还提供了一种将表达式分组的机制,当使用分组时,除了获得整个匹配。还能在匹配中选择每一个分组。
要实现分组,使用()即可。
例:
文本如下
张三:0571-88551166
使用表达式/(\d{4})-(\d{8})/g,匹配得到文本 0571-8855116.
那么这个文本实际分为了两组,第一组为0571,第二组为8855116.
2.6.2 非捕获分组
有时候,我们并不需要捕获某个分组的内容,但是又想使用分组的特性。
这时候就可以使用非捕获分组(?:表达式),从而不捕获数据,还能使用分组的功能。
2.6.3 分组回溯引用
正则表达式提供了一种引用之前匹配分组的机制,有些时候,我们或许会寻找到一个子匹配,该匹配接下来会再次出现。
例:
文本如下
<font>提示</font>
<font>提示</bar>
希望匹配正确的标签,可以使用 <(\w+?)>(.*?)<\/\1>这里\1表示第一个括号中的内容,这样就可以使用回溯分组调用,调用第一个括号的内容。
最终匹配到了正确的文本
<font>提示</font>
注:在java程序中,可以使用 $n 来使用捕获的第n个内容,如
string.replaceAll("<(.*)>", "$1 ");
三、经典正则表达式
由26个字母和数字组成的字符串:
^[A-Za-z0-9]+\$匹配中文字符:
[\u4e00-\u9fa5]没有空字符的且以tmp结尾的文件(^在中括号中表示取反,在中括号外表示开头):
[^ ]*.tmp匹配html标签:
<.+?>只需要添加懒惰匹配符号?,让<>来匹配每个标签匹配颜色标签符,如#ffffff:
#[a-fA-F0-9]{6}\b,添加\b是为了防止#ffffffff这种被识别为颜色标签符正整数*:
^\d+$负整数:
^-\d+$国内电话号码:
\d{3}-\d{8}|\d{4}-\d{7}手机国家号:
^+?[\d\s]{3,}$手机号:
^+?[\d\s]+(?[\d\s]{10,}$整数:
^-?\d+$用户名:
^[\w\d_.]{4,16}$数字和英文字母:
^[a-zA-Z0-9]*$数字和应为字母和空格:
^[a-zA-Z0-9 ]*$密码(至少一个大写字母、至少一个小写字母、至少一个数字、至少8个字符):
/(?=.*?[a-z])(?=.*?[A-Z])(?=.*?(\d)).{8,}/g密码:
^(?=^.{6,}$)((?=.*[A-Za-z0-9])(?=.*[A-Z])(?=.*[a-z]))^.*$邮箱:
^([a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4})*$IP4 地址:
^((?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))*$纯小写字母:
^([a-z])*$纯大写字母:
^([A-Z])*$URL:
^(((http|https|ftp):\/\/)?([[a-zA-Z0-9]\-\.])+(\.)([[a-zA-Z0-9]]){2,4}([[a-zA-Z0-9]\/+=%&_\.~?\-]*))*$VISA 信用卡号:
^(4[0-9]{12}(?:[0-9]{3})?)*$日期 (MM/DD/YYYY):
^(0?[1-9]|1[012])[- /.](0?[1-9]|[12][0-9]|3[01])[- /.](19|20)?[0-9]{2}$日期 (YYYY/MM/DD):
^(19|20)?[0-9]{2}[- /.](0?[1-9]|1[012])[- /.](0?[1-9]|[12][0-9]|3[01])$MasterCard 信用卡号:
^(5[1-5][0-9]{14})*$
IP地址(需要分为四段):
0-99:[1-9]?\d
100-199:1\d{2}
200-249:2[0-4]\d
250-256:25[0-5]
(([1-9]?\d|1\d{2}|2[0-4]\d|25[0-5]).){3}([1-9]?\d|1\d{2}|2[0-4]\d|25[0-5])