type
status
date
slug
summary
tags
category
icon
password
一、简介
正则表达式(regular expression)描述了一种字符串匹配的模式(pattern),由普通字符(例如字符 a 到 z)以及特殊字符(称为"元字符")组成的文字模式。可以用来完成下面工作:
- 检查一个串是否含有某种子串
- 将匹配的子串替换
- 从某个串中取出符合某个条件的子串
正则表达式一般写在两个
/
里面,类似于 /regex/
的格式。例如下面是一个比较简单的正则表达式,表示包含0的任意整数。这个正则表达式的目的是用来匹配字符的。以 java 为例,java 的正则表达式不需要写
/
,但是遇到 \
的时候需要加一个转义字符 \
,例如 ^\d+$
要写成 ^\\d+$
。二、正则表达式字符
正则表达式的字符分为 普通字符 和 元字符 两种:
- 普通字符:指没有显式指定为元字符的所有可打印和不可打印字符。这包括所有大写和小写字母、所有数字、所有标点符号和一些其他符号。
- 元字符:指有特殊含义的字符,这些字符会被解释成其他意思。元字符包括字符类字符(部分以
\
开头)、反义元字符、限定字符、定位符等。
例如下面这个正则表达式,用来匹配 abc 开头,后面是任意整数的字符串。
这个正则表达式里面:
/
:首尾两个/
表示这是一个正则表达式。
abc
:这三个是普通字符,用来精确匹配字符abc
。
^
\d
+
$
:这四个是元字符,字符含义可以参考下面的介绍。
要查找元字符本身,需要在元字符前面添加转义符
\
。例如要查找 .
和 *
本身符号,需要使用 \.
和 \*
。包括查找 \
本身,也需要用 \\
。例如:deerchao\.cn
匹配 deerchao.cnC:\\Windows
匹配 C:\Windows1、字符类元字符
字符类元字符一般会被解释成某类字符,例如英文、数字、空格等。常见元字符:
代码 | 说明 |
. | 匹配除换行符(\n、\r)以外的任意字符,相等于 [^\n\r] |
\ | 将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。例如, 'n' 匹配字符 'n'。'\n' 匹配换行符。序列 '\' 匹配 "",而 '(' 则匹配 "("。 |
() | 标记一个子表达式的开始和结束位置 |
[] | 匹配中括号里面的任意一个字符即可。例如[aeiou]表示匹配a、e、i、o、u的任意一个字母即可,[A-Z]表示一个区间,匹配所有大写字母。[a-z] 匹配所有小写字母。[0-9]匹配所有数字,等同于\d。[a-z0-9A-Z_]等同于\w。 |
{} | 标记一个限定符表达式的开始和结束位置 |
\a | 报警字符(打印它的效果是电脑嘀一声) |
\w | 匹配字母或数字或下划线或汉字 |
\s | 匹配任意的空白符 |
\d | 匹配数字 |
\b | 匹配单词的开始或结束 |
\f | 匹配一个换页符。等价于 \x0c 和 \cL。 |
\n | 匹配一个换行符。等价于 \x0a 和 \cJ。 |
\r | 匹配一个回车符。等价于 \x0d 和 \cM。 |
\s | 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。注意 Unicode 正则表达式会匹配全角空格符。 |
\t | 匹配一个制表符。等价于 \x09 和 \cI。 |
\v | 匹配一个垂直制表符。等价于 \x0b 和 \cK。 |
\cN | ASCII控制字符。比如\cC代表Ctrl+C |
\0nn | ASCII代码中八进制代码为nn的字符 |
\xnn | ASCII代码中十六进制代码为nn的字符 |
\unnnn | Unicode代码中十六进制代码为nnnn的字符 |
括号()
、中括号[]
、大括号{}
的区别:
()
表示的是一个子表达式,()
本身不匹配任何东西,也不限制匹配任何东西,只是把括号内的内容作为同一个表达式来处理。
(abc|bcd|cde)
表示这一段是abc、bcd、cde三者之一均可,顺序也必须一致(abc)?
表示这一组要么一起出现,要么不出现
[]
表示匹配中括号里面的任意一个字符即可,只能匹配[]
里面的单个字符,并且特殊字符写在[]
会被当成普通字符来匹配。
[0-3]
表示找到这一个位置上的字符只能是0到3这四个数字,与(abc|bcd|cde)
的作用比较类似,但圆括号可以匹配多个连续的字符,而方括号只能匹配单个字符[(a)]
表示匹配(
、a
、)
、这三个字符。
{}
表示匹配的长度,作用于紧挨的前一个表达式。{n}
表示重复n次,{n,m}
表示重复n到m次。
(ab){3}
表示ab必须出现3次。(ab){1,3}
表示ab一起连续出现最少1次,最多3次。ab{1,3}
表示a后面紧跟的b出现最少1次,最多3次。
3、反义元字符
有时需要查找不属于某个能简单定义的字符类的字符。比如想查找除了数字以外,其它任意字符都行的情况,这时需要用到反义。
代码 | 说明 |
\W | 匹配任意不是字母,数字,下划线,汉字的字符 |
\S | 匹配任意不是空白符的字符 |
\D | 匹配任意非数字的字符 |
\B | 匹配不是单词开头或结束的位置 |
[^x] | 匹配除了x以外的任意字符 |
[^aeiou] | 匹配除了aeiou这几个字母以外的任意字符 |
例如:
\S+
匹配不包含空白符的字符串。<a[^>]+>
匹配用尖括号括起来的以a开头的字符串。4、限定符
限定符用来指定正则表达式的一个给定组件必须要出现多少次才能满足匹配。
代码 | 说明 |
* | 重复零次或更多次 |
+ | 重复一次或更多次 |
? | 重复零次或一次 |
{n} | 重复n次 |
{n,} | 重复n次或更多次 |
{n,m} | 重复n到m次 |
例如:
Windows\d+
匹配Windows后面跟1个或更多数字^\w+
匹配一行的第一个单词(或整个字符串的第一个单词,具体匹配哪个意思得看选项设置)5、定位符
定位符用来描述字符串或单词的边界。例如正则表达式
/hi/
会匹配所有包含hi的单词,例如him,history,high。如果我们想精确匹配hi这个单词,需要写成 /\bhi\b/
。常见定位符号如下:代码 | 说明 |
^ | 匹配字符串的开始 |
$ | 匹配字符串的结束 |
\b | 匹配单词的开始或结束 |
\B | 匹配不是单词开头或结束的位置 |
注意:不能将限定符与定位符一起使用。由于在紧靠换行或者单词边界的前面或后面不能有一个以上位置,因此不允许诸如
^*
之类的表达式。- 若要匹配一行文本开始处的文本,请在正则表达式的开始使用
^
字符。不要将^
的这种用法与中括号表达式内的用法混淆。
- 若要匹配一行文本的结束处的文本,请在正则表达式的结束处使用
$
字符。
6、多选分支
正则表达式里的分枝条件指的是有几种规则,每种规则用
()
括起来,不同的规则用 |
分隔开,如果满足其中任意一种规则都应该当成匹配成功。代码 | 说明 |
() | 每个小括号都是一组子表达式,一个正则表达式可以包含多个子表达式 |
| | 连接多个子表达式,从左到右满足其中一个子表达式就算匹配成功,就不会再往后面查找 |
例如:
(\d{1,3}\.){3}\d{1,3}
是一个简单的IP地址匹配表达式,匹配三位数字加上一个英文句号(这个整体也就是这个分组)重复3次,最后再加上一个一到三位的数字。7、贪婪与懒惰
贪婪和懒惰模式:
- 贪婪模式:默认模式,当正则表达式中包含能接受重复的限定符时,通常的行为是在使整个表达式能得到匹配的前提下
匹配尽可能多的字符
。
- 懒惰模式:匹配任意数量的重复,但是在能使整个匹配成功的前提下
匹配尽可能少的字符
。开启懒惰模式只需要在限定符后面加?
。
例如对于字符串
aabab
,匹配最长的以a开始,以b结束的字符串。,- 使用贪婪模式正则
/a.*b/
,匹配字符串aabab
。
- 使用懒惰模式正则
/a.*?b/
,匹配字符串aab
。
代码 | 说明 |
*? | 重复任意次,但尽可能少重复 |
+? | 重复1次或更多次,但尽可能少重复 |
?? | 重复0次或1次,但尽可能少重复 |
{n,m}? | 重复n到m次,但尽可能少重复 |
{n,}? | 重复n次以上,但尽可能少重复 |
8、零宽断言
零宽断言用于断言某些位置(可以是之前或者之后,但不包括位置本身)应该满足的表达式。这些内容只用于匹配某些位置,在匹配过程中不占用字符,所以被称为"零宽"。
比如
\b(?=re)\w+\b
,匹配以 re
开头的单词的后面除了 re
以外的部分,如查找 reading a book.
时,它会匹配 ading
。零宽断言分为四种:
代码 | 说明 | 举例 |
(?=pattern) | 零宽正向先行断言,断言自身位置的后面能匹配表达式 pattern | \b\w+(?<=ing\b) 会匹配以 ing 结尾的单词除了 ing 以外的前面部分,例如在查找 I am reading. 时,它匹配 read 。 |
(?<=pattern) | 零宽正向后行断言,断言自身位置的前面能匹配表达式 pattern
| (?<=\bre)\w+\b 会匹配以 re 开头的单词除了 re 以外的后面部分,例如在查找 reading a book 时,它匹配 ading 。 |
(?!pattern) | 零宽负向先行断言,断言自身位置的后面不能匹配表达式 pattern | \d{3}(?!\d) 匹配三位数字,而且这三位数字的后面不能是数字。
\b((?!abc)\w)+\b 匹配不包含连续字符串 abc 的单词。 |
(?<!pattern) | 零宽负向后行断言,断言自身位置的前面不能匹配表达式 pattern | (?<[a-z])\d{7} 匹配前面不是小写字母的七位数字。 |
例如:
对
regex represents regular expression
这个字符串:- 正向先行断言:要想匹配
regular
中的re
,但不能匹配expression
中的re
,可以用re(?=gular)
。
- 正向后行断言:要想匹配单词内部的
re
,但不匹配单词开头的re
,可以用(?<=\w)re
,该表达式限定了在re
前面应该是一个单词字符。
- 负向先行断言:要想匹配除
regex
和regular
之外的re
,可以用re(?!g)
,该表达式限定了re
右边的位置,这个位置后面不是字符g
。
- 负向后行断言:要想匹配单词开头的 re,可以用
(?<!\w)re
。该表达式限定了re
前面不是单词字符。
9、后向引用
使用
()
指定一个子表达式后,该子表达式的相关匹配存储到一个临时缓冲区中。如果有多个子表达式,所捕获的每个子匹配都按照在正则表达式模式中从左到右出现的顺序存储。缓冲区编号从 1 开始,最多可存储 99 个捕获的子表达式。每个缓冲区都可以使用
\n
访问。例如 \1
表示捕获的第一个缓冲区。一般情况下,当匹配到第一个子表达式,就会继续向下匹配第二个子表达式。但是某些情况下如果我们想使用第一个子表达式匹配到的内容,在后面的文本中再进行匹配,这就需要用到
\1
缓冲区。这就是后向引用
。例如:
字符串
Is is the cost of of gasoline going up up?
,我们想匹配其中的重复单词 of of
和 up up
,可以使用正则表达式 \b([a-z]+)\s+\1\b
匹配。我们也可以来重写捕获区名称或者不捕获匹配内容。
代码 | 说明 |
(exp) | 匹配exp,并捕获文本到自动命名的组里 |
(?<name>exp) | 匹配exp,并捕获文本到名称为name的组里,也可以写成(?'name'exp) |
(?:exp) | 匹配exp,不捕获匹配的文本,也不给此分组分配组号 |
10、注释
有时候正则表达式复杂,我们可以在正则表达式里面添加注释来提高易读性。
代码 | 说明 |
(?#comment) | 这种类型的分组不对正则表达式的处理产生任何影响,用于提供注释让人阅读 |
四、常用示例
1、检验数字的正则表达式
- 数字:^[0-9]*$
- n位的数字:^\d{n}$
- 至少n位的数字:^\d{n,}$
- m-n位的数字:^\d{m,n}$
- 零和非零开头的数字:^(0|[1-9][0-9]*)$
- 非零开头的最多带两位小数的数字:^([1-9][0-9]*)+(.[0-9]{1,2})?$
- 带1-2位小数的正数或负数:^(-)?\d+(.\d{1,2})$
- 正数、负数、和小数:^(-|+)?\d+(.\d+)?$
- 有两位小数的正实数:^[0-9]+(.[0-9]{2})?$
- 有1~3位小数的正实数:^[0-9]+(.[0-9]{1,3})?$
- 非零的正整数:^[1-9]\d*$ 或 ^([1-9][0-9]){1,3}$ 或 ^+?[1-9][0-9]$
- 非零的负整数:^-[1-9][]0-9"$ 或 ^-[1-9]\d$
- 非负整数:^\d+$ 或 ^[1-9]\d*|0$
- 非正整数:^-[1-9]\d*|0$ 或 ^((-\d+)|(0+))$
- 非负浮点数:^\d+(.\d+)?$ 或 ^[1-9]\d*.\d*|0.\d*[1-9]\d*|0?.0+|0$
- 非正浮点数:^((-\d+(.\d+)?)|(0+(.0+)?))$ 或 ^(-([1-9]\d*.\d*|0.\d*[1-9]\d*))|0?.0+|0$
- 正浮点数:^[1-9]\d*.\d*|0.\d*[1-9]\d*$ 或 ^(([0-9]+.[0-9][1-9][0-9])|([0-9][1-9][0-9].[0-9]+)|([0-9][1-9][0-9]))$
- 负浮点数:^-([1-9]\d*.\d*|0.\d*[1-9]\d*)$ 或 ^(-(([0-9]+.[0-9][1-9][0-9])|([0-9][1-9][0-9].[0-9]+)|([0-9][1-9][0-9])))$
- 浮点数:^(-?\d+)(.\d+)?$ 或 ^-?([1-9]\d*.\d*|0.\d*[1-9]\d*|0?.0+|0)$
2、校验字符的表达式
- 汉字:^[\u4e00-\u9fa5]{0,}$
- 英文和数字:^[A-Za-z0-9]+$ 或 ^[A-Za-z0-9]{4,40}$
- 长度为3-20的所有字符:^.{3,20}$
- 由26个英文字母组成的字符串:^[A-Za-z]+$
- 由26个大写英文字母组成的字符串:^[A-Z]+$
- 由26个小写英文字母组成的字符串:^[a-z]+$
- 由数字和26个英文字母组成的字符串:^[A-Za-z0-9]+$
- 由数字、26个英文字母或者下划线组成的字符串:^\w+$ 或 ^\w{3,20}$
- 中文、英文、数字包括下划线:^[\u4E00-\u9FA5A-Za-z0-9_]+$
- 中文、英文、数字但不包括下划线等符号:^[\u4E00-\u9FA5A-Za-z0-9]+$ 或 ^[\u4E00-\u9FA5A-Za-z0-9]{2,20}$
- 可以输入含有^%&',;=?\"等字符:[^%&',;=?\x22]+
- 禁止输入含有~的字符:[^~]+
3、特殊需求表达式
- Email地址:^\w+([-+.]\w+)@\w+([-.]\w+).\w+([-.]\w+)*$
- 域名:[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+.?
- InternetURL:[a-zA-z]+://[^\s]* 或 ^http://([\w-]+.)+[\w-]+(/[\w-./?%&=]*)?$
- 手机号码:^(13[0-9]|14[5|7]|15[0|1|2|3|4|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$
- 电话号码("XXX-XXXXXXX"、"XXXX-XXXXXXXX"、"XXX-XXXXXXX"、"XXX-XXXXXXXX"、"XXXXXXX"和"XXXXXXXX):^((\d{3,4}-)|\d{3.4}-)?\d{7,8}$
- 国内电话号码(0511-4405222、021-87888822):\d{3}-\d{8}|\d{4}-\d{7}
- 电话号码正则表达式(支持手机号码,3-4位区号,7-8位直播号码,1-4位分机号): ((\d{11})|^((\d{7,8})|(\d{4}|\d{3})-(\d{7,8})|(\d{4}|\d{3})-(\d{7,8})-(\d{4}|\d{3}|\d{2}|\d{1})|(\d{7,8})-(\d{4}|\d{3}|\d{2}|\d{1}))$)
- 身份证号(15位、18位数字),最后一位是校验位,可能为数字或字符X:(^\d{15})|(^\d{18})|(^\d{17}(\d|X|x)$)
- 帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
- 密码(以字母开头,长度在6~18之间,只能包含字母、数字和下划线):^[a-zA-Z]\w{5,17}$
- 强密码(必须包含大小写字母和数字的组合,不能使用特殊字符,长度在 8-10 之间):^(?=.\d)(?=.[a-z])(?=.*[A-Z])[a-zA-Z0-9]{8,10}$
- 强密码(必须包含大小写字母和数字的组合,可以使用特殊字符,长度在8-10之间):^(?=.\d)(?=.[a-z])(?=.*[A-Z]).{8,10}$
- 日期格式:^\d{4}-\d{1,2}-\d{1,2}
- 一年的12个月(01~09和1~12):^(0?[1-9]|1[0-2])$
- 一个月的31天(01~09和1~31):^((0?[1-9])|((1|2)[0-9])|30|31)$
- 钱的输入格式:
- 有四种钱的表示形式我们可以接受:"10000.00" 和 "10,000.00", 和没有 "分" 的 "10000" 和 "10,000":^[1-9][0-9]*$
- 这表示任意一个不以0开头的数字,但是,这也意味着一个字符"0"不通过,所以我们采用下面的形式:^(0|[1-9][0-9]*)$
- 一个0或者一个不以0开头的数字.我们还可以允许开头有一个负号:^(0|-?[1-9][0-9]*)$
- 这表示一个0或者一个可能为负的开头不为0的数字.让用户以0开头好了.把负号的也去掉,因为钱总不能是负的吧。下面我们要加的是说明可能的小数部分:^[0-9]+(.[0-9]+)?$
- 必须说明的是,小数点后面至少应该有1位数,所以"10."是不通过的,但是 "10" 和 "10.2" 是通过的:^[0-9]+(.[0-9]{2})?$
- 这样我们规定小数点后面必须有两位,如果你认为太苛刻了,可以这样:^[0-9]+(.[0-9]{1,2})?$
- 这样就允许用户只写一位小数.下面我们该考虑数字中的逗号了,我们可以这样:^[0-9]{1,3}(,[0-9]{3})*(.[0-9]{1,2})?$
- 1到3个数字,后面跟着任意个 逗号+3个数字,逗号成为可选,而不是必须:^([0-9]+|[0-9]{1,3}(,[0-9]{3})*)(.[0-9]{1,2})?$
- 备注:这就是最终结果了,别忘了"+"可以用"*"替代如果你觉得空字符串也可以接受的话(奇怪,为什么?)最后,别忘了在用函数时去掉去掉那个反斜杠,一般的错误都在这里
- xml文件:^([a-zA-Z]+-?)+[a-zA-Z0-9]+\.[x|X][m|M][l|L]$
- 中文字符的正则表达式:[\u4e00-\u9fa5]
- 双字节字符:[^\x00-\xff] (包括汉字在内,可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1))
- 空白行的正则表达式:\n\s*\r (可以用来删除空白行)
- HTML标记的正则表达式:<(\S*?)[^>]>.?|<.? /> ( 首尾空白字符的正则表达式:^\s|\s*或(^\s*)|(\s*) (可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式)
- 腾讯QQ号:[1-9][0-9]{4,} (腾讯QQ号从10000开始)
- 中国邮政编码:[1-9]\d{5}(?!\d) (中国邮政编码为6位数字)
- IPv4地址:((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})(.((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})){3}
- 不是以abc开始的行:^(?!abc).*$
- Author:mcbilla
- URL:http://mcbilla.com/article/5281ec01-5d73-484d-bb3c-cb5a15613db9
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!