Appearance
正则表达式
什么是正则表达式?
正则表达式是一组由字母和符号组成的特殊文本, 它可以用来从文本中找出满足你想要的格式的句子.
一个正则表达式是在一个主体字符串中从左到右匹配字符串时的一种样式.
"Regular expression"这个词比较拗口, 我们常使用缩写的术语"regex"或"regexp".
正则表达式可以从一个基础字符串中根据一定的匹配模式替换文本中的字符串、验证表单、提取字符串等等.
想象你正在写一个应用, 然后你想设定一个用户命名的规则, 让用户名包含字符,数字,下划线和连字符,以及限制字符的个数,好让名字看起来没那么丑.
我们使用以下正则表达式来验证一个用户名:
以上的正则表达式可以接受 john_doe
, jo-hn_doe
, john12_as
.
但不匹配Jo
, 因为它包含了大写的字母而且太短了.
目录
1. 基本匹配
正则表达式其实就是在执行搜索时的格式, 它由一些字母和数字组合而成.
例如: 一个正则表达式 the
, 它表示一个规则: 由字母t
开始,接着是h
,再接着是e
.
正则表达式123
匹配字符串123
. 它逐个字符的与输入的正则表达式做比较.
正则表达式是大小写敏感的, 所以The
不会匹配the
.
2. 元字符
正则表达式主要依赖于元字符.
元字符不代表他们本身的字面意思, 他们都有特殊的含义. 一些元字符写在方括号中的时候有一些特殊的意思. 以下是一些元字符的介绍:
元字符 | 描述 |
---|---|
. | 句号匹配任意单个字符除了换行符. |
[ ] | 字符种类. 匹配方括号内的任意字符. |
[^ ] | 否定的字符种类. 匹配除了方括号里的任意字符 |
* | 匹配>=0个重复的在*号之前的字符. |
+ | 匹配>=1个重复的+号前的字符. |
? | 标记?之前的字符为可选. |
匹配num个大括号之前的字符 (n <= num <= m). | |
(xyz) | 字符集, 匹配与 xyz 完全相等的字符串. |
| | 或运算符,匹配符号前或后的字符. |
|转义字符,用于匹配一些保留的字符 `[ ] ( ) { } . * + ? ^ $ \ | |
^ | 从开始行开始匹配. |
$ | 从末端开始匹配. |
2.1 点运算符 .
.
是元字符中最简单的例子.
.
匹配任意单个字符, 但不匹配换行符.
例如, 表达式.ar
匹配一个任意字符后面跟着是a
和r
的字符串.
2.2 字符集
字符集也叫做字符类.
方括号用来指定一个字符集.
在方括号中使用连字符来指定字符集的范围.
在方括号中的字符集不关心顺序.
例如, 表达式[Tt]he
匹配 the
和 The
.
方括号的句号就表示句号.
表达式 ar[.]
匹配 ar.
字符串
2.2.1 否定字符集
一般来说 ^
表示一个字符串的开头, 但它用在一个方括号的开头的时候, 它表示这个字符集是否定的.
例如, 表达式[^c]ar
匹配一个后面跟着ar
的除了c
的任意字符.
2.3 重复次数
后面跟着元字符 +
, *
or ?
的, 用来指定匹配子模式的次数.
这些元字符在不同的情况下有着不同的意思.
2.3.1 *
号
*
号匹配 在*
之前的字符出现大于等于0
次.
例如, 表达式 a*
匹配以0或更多个a开头的字符, 因为有0个这个条件, 其实也就匹配了所有的字符. 表达式[a-z]*
匹配一个行中所有以小写字母开头的字符串.
*
字符和.
字符搭配可以匹配所有的字符.*
.
*
和表示匹配空格的符号\s
连起来用, 如表达式\s*cat\s*
匹配0或更多个空格开头和0或更多个空格结尾的cat字符串.
2.3.2 +
号
+
号匹配+
号之前的字符出现 >=1 次.
例如表达式c.+t
匹配以首字母c
开头以t
结尾,中间跟着任意个字符的字符串.
2.3.3 ?
号
在正则表达式中元字符 ?
标记在符号前面的字符为可选, 即出现 0 或 1 次.
例如, 表达式 [T]?he
匹配字符串 he
和 The
.
2.4 {}
号
在正则表达式中 {}
是一个量词, 常用来一个或一组字符可以重复出现的次数.
例如, 表达式 [0-9]{2,3}
匹配最少 2 位最多 3 位 0~9 的数字.
我们可以省略第二个参数.
例如, [0-9]{2,}
匹配至少两位 0~9 的数字.
如果逗号也省略掉则表示重复固定的次数.
例如, [0-9]{3}
匹配3位数字
2.5 (...)
特征标群
特征标群是一组写在 (...)
中的子模式. 例如之前说的 {}
是用来表示前面一个字符出现指定次数. 但如果在 {}
前加入特征标群则表示整个标群内的字符重复 N 次. 例如, 表达式 (ab)*
匹配连续出现 0 或更多个 ab
.
我们还可以在 ()
中用或字符 |
表示或. 例如, (c|g|p)ar
匹配 car
或 gar
或 par
.
2.6 |
或运算符
或运算符就表示或, 用作判断条件.
例如 (T|t)he|car
匹配 (T|t)he
或 car
.
2.7 转码特殊字符
反斜线 \
在表达式中用于转码紧跟其后的字符. 用于指定 { } [ ] / \ + * . $ ^ | ?
这些特殊字符. 如果想要匹配这些特殊字符则要在其前面加上反斜线 \
.
例如 .
是用来匹配除换行符外的所有字符的. 如果想要匹配句子中的 .
则要写成 \.
以下这个例子 \.?
是选择性匹配.
2.8 锚点
在正则表达式中, 想要匹配指定开头或结尾的字符串就要使用到锚点. ^
指定开头, $
指定结尾.
2.8.1 ^
号
^
用来检查匹配的字符串是否在所匹配字符串的开头.
例如, 在 abc
中使用表达式 ^a
会得到结果 a
. 但如果使用 ^b
将匹配不到任何结果. 因为在字符串 abc
中并不是以 b
开头.
例如, ^(T|t)he
匹配以 The
或 the
开头的字符串.
2.8.2 $
号
同理于 ^
号, $
号用来匹配字符是否是最后一个.
例如, (at\.)$
匹配以 at.
结尾的字符串.
3. 简写字符集
正则表达式提供一些常用的字符集简写. 如下:
简写 | 描述 |
---|---|
. | 除换行符外的所有字符 |
\w | 匹配所有字母数字, 等同于 [a-zA-Z0-9_] |
\W | 匹配所有非字母数字, 即符号, 等同于: [^\w] |
\d | 匹配数字: [0-9] |
\D | 匹配非数字: [^\d] |
\s | 匹配所有空格字符, 等同于: [\t\n\f\r\p{Z}] |
\S | 匹配所有非空格字符: [^\s] |
\f | 匹配一个换页符 |
\n | 匹配一个换行符 |
\r | 匹配一个回车符 |
\t | 匹配一个制表符 |
\v | 匹配一个垂直制表符 |
\p | 匹配 CR/LF (等同于 \r\n ),用来匹配 DOS 行终止符 |
4. 零宽度断言(前后预查)
先行断言和后发断言都属于非捕获簇(不捕获文本 ,也不针对组合计进行计数).
先行断言用于判断所匹配的格式是否在另一个确定的格式之前, 匹配结果不包含该确定格式(仅作为约束).
例如, 我们想要获得所有跟在 $
符号后的数字, 我们可以使用正后发断言 (?<=\$)[0-9\.]*
.
这个表达式匹配 $
开头, 之后跟着 0,1,2,3,4,5,6,7,8,9,.
这些字符可以出现大于等于 0 次.
零宽度断言如下:
符号 | 描述 |
---|---|
?= | 正先行断言-存在 |
?! | 负先行断言-排除 |
?<= | 正后发断言-存在 |
?<! | 负后发断言-排除 |
4.1 ?=...
正先行断言
?=...
正先行断言, 表示第一部分表达式之后必须跟着 ?=...
定义的表达式.
返回结果只包含满足匹配条件的第一部分表达式.
定义一个正先行断言要使用 ()
. 在括号内部使用一个问号和等号: (?=...)
.
正先行断言的内容写在括号中的等号后面.
例如, 表达式 (T|t)he(?=\sfat)
匹配 The
和 the
, 在括号中我们又定义了正先行断言 (?=\sfat)
,即 The
和 the
后面紧跟着 (空格)fat
.
4.2 ?!...
负先行断言
负先行断言 ?!
用于筛选所有匹配结果, 筛选条件为 其后不跟随着断言中定义的格式.
正先行断言
定义和 负先行断言
一样, 区别就是 =
替换成 !
也就是 (?!...)
.
表达式 (T|t)he(?!\sfat)
匹配 The
和 the
, 且其后不跟着 (空格)fat
.
4.3 ?<= ...
正后发断言
正后发断言 记作(?<=...)
用于筛选所有匹配结果, 筛选条件为 其前跟随着断言中定义的格式.
例如, 表达式 (?<=(T|t)he\s)(fat|mat)
匹配 fat
和 mat
, 且其前跟着 The
或 the
.
4.4 ?<!...
负后发断言
负后发断言 记作 (?<!...)
用于筛选所有匹配结果, 筛选条件为 其前不跟随着断言中定义的格式.
例如, 表达式 (?<!(T|t)he\s)(cat)
匹配 cat
, 且其前不跟着 The
或 the
.
5. 标志
标志也叫模式修正符, 因为它可以用来修改表达式的搜索结果.
这些标志可以任意的组合使用, 它也是整个正则表达式的一部分.
标志 | 描述 |
---|---|
i | 忽略大小写. |
g | 全局搜索. |
m | 多行的: 锚点元字符 ^ $ 工作范围在每行的起始. |
5.1 忽略大小写 (Case Insensitive)
修饰语 i
用于忽略大小写.
例如, 表达式 /The/gi
表示在全局搜索 The
, 在后面的 i
将其条件修改为忽略大小写, 则变成搜索 the
和 The
, g
表示全局搜索.
5.2 全局搜索 (Global search)
修饰符 g
常用于执行一个全局搜索匹配, 即(不仅仅返回第一个匹配的, 而是返回全部).
例如, 表达式 /.(at)/g
表示搜索 任意字符(除了换行) + at
, 并返回全部结果.
5.3 多行修饰符 (Multiline)
多行修饰符 m
常用语执行一个多行匹配.
像之前介绍的 (^,$)
用于检查格式是否是在待检测字符串的开头或结尾. 但我们如果想要它在每行的开头和结尾生效, 我们需要用到多行修饰符 m
.
例如, 表达式 /at(.)?$/gm
表示小写字符 a
后跟小写字符 t
, 末尾可选除换行符外任意字符. 根据 m
修饰符, 现在表达式匹配每行的结尾.
6. 贪婪匹配与惰性匹配 (Greedy vs lazy matching)
正则表达式默认采用贪婪匹配模式,在该模式下意味着会匹配尽可能长的子串。我们可以使用 ?
将贪婪匹配模式转化为惰性匹配模式。
常见正则表达式
一、校验数字的表达式
- **数字:**
<span class="ne-text">^[0-9]*$</span>
- **n 位的数字:**
<span class="ne-text">^\d{n}$</span>
- **至少 n 位的数字:**
<span class="ne-text">^\d{n,}$</span>
- **m-n 位的数字:**
<span class="ne-text">^\d{m,n}$</span>
- **零和非零开头的数字:**
<span class="ne-text">^(0|[1-9][0-9]*)$</span>
- **非零开头的最多带两位小数的数字:**
<span class="ne-text">^([1-9][0-9]*)+(.[0-9]{1,2})?$</span>
- **带 1-2 位小数的正数或负数:**
<span class="ne-text">^(-)?\d+(.\d{1,2})?$</span>
- **正数、负数、和小数:**
<span class="ne-text">^(-|+)?\d+(.\d+)?$</span>
- **有两位小数的正实数:**
<span class="ne-text">^[0-9]+(.[0-9]{2})?$</span>
- **有 1~3 位小数的正实数:**
<span class="ne-text">^[0-9]+(.[0-9]{1,3})?$</span>
- **非零的正整数:**
<span class="ne-text">^[1-9]\d$</span>
或<span class="ne-text">^([1-9][0-9]){1,3}$</span>
或<span class="ne-text">^+?[1-9][0-9]*$</span>
- **非零的负整数:**
<span class="ne-text">^-[1-9][]0-9"$</span>
或<span class="ne-text">^-[1-9]\d$</span>
- **非负整数:**
<span class="ne-text">^\d+$</span>
或<span class="ne-text">^[1-9]\d*|0$</span>
- **非正整数:**
<span class="ne-text">^-[1-9]\d*|0$</span>
或<span class="ne-text">^((-\d+)|(0+))$</span>
- **非负浮点数:**
<span class="ne-text">^\d+(.\d+)?$</span>
或<span class="ne-text">^[1-9]\d.\d|0.\d[1-9]\d|0?.0+|0$</span>
- **非正浮点数:**
<span class="ne-text">^((-\d+(.\d+)?)|(0+(.0+)?))$</span>
或<span class="ne-text">^(-([1-9]\d.\d|0.\d[1-9]\d))|0?.0+|0$</span>
- **正浮点数:**
<span class="ne-text">^[1-9]\d.\d|0.\d[1-9]\d$</span>
或<span class="ne-text">^(([0-9]+.[0-9][1-9][0-9])|([0-9][1-9][0-9].[0-9]+)|([0-9][1-9][0-9]))$</span>
- **负浮点数:**
<span class="ne-text">^-([1-9]\d.\d|0.\d[1-9]\d)$</span>
或<span class="ne-text">^(-(([0-9]+.[0-9][1-9][0-9])|([0-9][1-9][0-9].[0-9]+)|([0-9][1-9][0-9])))$</span>
- **浮点数:**
<span class="ne-text">^(-?\d+)(.\d+)?$</span>
或<span class="ne-text">^-?([1-9]\d.\d|0.\d[1-9]\d|0?.0+|0)$</span>
二、校验字符的表达式
- **汉字:**
<span class="ne-text">^[\u4e00-\u9fa5]{0,}$</span>
- **英文和数字:**
<span class="ne-text">^[A-Za-z0-9]+$</span>
或<span class="ne-text">^[A-Za-z0-9]{4,40}$</span>
- **长度为 3-20 的所有字符:**
<span class="ne-text">^.{3,20}$</span>
- **由 26 个英文字母组成的字符串:**
<span class="ne-text">^[A-Za-z]+$</span>
- **由 26 个大写英文字母组成的字符串:**
<span class="ne-text">^[A-Z]+$</span>
- **由 26 个小写英文字母组成的字符串:**
<span class="ne-text">^[a-z]+$</span>
- **由数字和 26 个英文字母组成的字符串:**
<span class="ne-text">^[A-Za-z0-9]+$</span>
- **由数字、26 个英文字母或者下划线组成的字符串:**
<span class="ne-text">^\w+$ 或 ^\w{3,20}$</span>
- **中文、英文、数字包括下划线:**
<span class="ne-text">^[\u4E00-\u9FA5A-Za-z0-9_]+$</span>
- **中文、英文、数字但不包括下划线等符号:**
<span class="ne-text">^[\u4E00-\u9FA5A-Za-z0-9]+$ 或 ^[\u4E00-\u9FA5A-Za-z0-9]{2,20}$</span>
- 可以输入含有
<span class="ne-text">^%&',;=?$\"</span>
等字符:<span class="ne-text">[^%&',;=?$\x22]+</span>
- **禁止输入含有~的字符:**
<span class="ne-text">[^~\x22]+</span>
三、特殊需求表达式
**Email 地址:**
<span class="ne-text">^\w+([-+.]\w+)@\w+([-.]\w+).\w+([-.]\w+)*$</span>
**域名:**
<span class="ne-text">[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.?</span>
**InternetURL:**
<span class="ne-text">[a-zA-z]+://[^\s] 或 ^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=])?$</span>
**手机号码:**
<span class="ne-text">^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$</span>
**电话号码("XXX-XXXXXXX"、"XXXX-XXXXXXXX"、"XXX-XXXXXXX"、"XXX-XXXXXXXX"、"XXXXXXX"和"XXXXXXXX):**
<span class="ne-text">^((\d{3,4}-)|\d{3.4}-)?\d{7,8}$</span>
**国内电话号码(0511-4405222、021-87888822):**
<span class="ne-text">\d{3}-\d{8}|\d{4}-\d{7}</span>
**身份证号(15 位、18 位数字):**
<span class="ne-text">^\d{15}|\d{18}$</span>
**短身份证号码(数字、字母 x 结尾):**
<span class="ne-text">^([0-9]){7,18}(x|X)?$</span>
或<span class="ne-text">^\d{8,18}|[0-9x]{8,18}|[0-9X]{8,18}?$</span>
**帐号是否合法(字母开头,允许 5-16 字节,允许字母数字下划线):**
<span class="ne-text">^[a-zA-Z][a-zA-Z0-9_]{4,15}$</span>
**密码(以字母开头,长度在 6~18 之间,只能包含字母、数字和下划线):**
<span class="ne-text">^[a-zA-Z]\w{5,17}$</span>
**强密码(必须包含大小写字母和数字的组合,不能使用特殊字符,长度在 8-10 之间):**
<span class="ne-text">^(?=.\d)(?=.[a-z])(?=.*[A-Z]).{8,10}$</span>
**日期格式:**
<span class="ne-text">^\d{4}-\d{1,2}-\d{1,2}</span>
**一年的 12 个月(01 ~ 09 和 1 ~ 12):**
<span class="ne-text">^(0?[1-9]|1[0-2])$</span>
**一个月的 31 天(01 ~ 09 和 1 ~ 31):**
<span class="ne-text">^((0?[1-9])|((1|2)[0-9])|30|31)$</span>
钱的输入格式:
- **有四种钱的表示形式我们可以接受:"10000.00" 和 "10,000.00", 和没有 "分" 的 "10000" 和 "10,000":**
<span class="ne-text">^[1-9][0-9]\*\$</span>
- **这表示任意一个不以 0 开头的数字,但是,这也意味着一个字符"0"不通过,所以我们采用下面的形式:**
<span class="ne-text">^(0|[1-9][0-9]\*)\$</span>
- **一个 0 或者一个不以 0 开头的数字.我们还可以允许开头有一个负号:**
<span class="ne-text">^(0|-?[1-9][0-9]\*)\$</span>
- **这表示一个 0 或者一个可能为负的开头不为 0 的数字.让用户以 0 开头好了.把负号的也去掉,因为钱总不能是负的吧.下面我们要加的是说明可能的小数部分:**
<span class="ne-text">^[0-9]+(.[0-9]+)?\$</span>
- **必须说明的是,小数点后面至少应该有 1 位数,所以"10."是不通过的,但是 "10" 和 "10.2" 是通过的:**
<span class="ne-text">^[0-9]+(.[0-9]{2})?\$</span>
- **这样我们规定小数点后面必须有两位,如果你认为太苛刻了,可以这样:**
<span class="ne-text">^[0-9]+(.[0-9]{1,2})?\$</span>
- **这样就允许用户只写一位小数.下面我们该考虑数字中的逗号了,我们可以这样:**
<span class="ne-text">^[0-9]{1,3}(,[0-9]{3})\*(.[0-9]{1,2})?\$</span>
- **1 到 3 个数字,后面跟着任意个 逗号+3 个数字,逗号成为可选,而不是必须:**
<span class="ne-text">^([0-9]+|[0-9]{1,3}(,[0-9]{3})_)(.[0-9]{1,2})?\$</span>
**备注:这就是最终结果了,别忘了"+"可以用" "替代如果你觉得空字符串也可以接受的话(奇怪,为什么?)最后,别忘了在用函数时去掉去掉那个反斜杠,一般的错误都在这里
- **有四种钱的表示形式我们可以接受:"10000.00" 和 "10,000.00", 和没有 "分" 的 "10000" 和 "10,000":**
**xml 文件:**
<span class="ne-text">^([a-zA-Z]+-?)+[a-zA-Z0-9]+\.[x|X][m|M][l|L]$</span>
**中文字符的正则表达式:**
<span class="ne-text">[\u4e00-\u9fa5]</span>
**双字节字符:**
<span class="ne-text">[^\x00-\xff]</span>
(包括汉字在内,可以用来计算字符串的长度(一个双字节字符长度计 2,ASCII 字符计 1))**空白行的正则表达式:**
<span class="ne-text">\n\s*\r</span>
(可以用来删除空白行)**首尾空白字符的正则表达式:**
<span class="ne-text">^\s|\s$或(^\s)|(\s$)</span>
(可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式)**腾讯 QQ 号:**
<span class="ne-text">[1-9][0-9]{4,}</span>
(腾讯 QQ 号从 10000 开始)**中国邮政编码:**
<span class="ne-text">[1-9]\d{5}(?!\d)</span>
(中国邮政编码为 6 位数字)**IP 地址:**
<span class="ne-text">\d+.\d+.\d+.\d+</span>
(提取 IP 地址时有用)**IP 地址:**
<span class="ne-text">((?:(?:25[0-5]|2[0-4]\d|[01]?\d?\d)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d?\d))</span>