1.1 正则表达式常见语法
在正则表达式的字符中,一般有2种,普通字符和元字符。普通字符表示在源文本中直接匹配。如果你要找所有的test
,正则表达式就非常简单,直接输入test
即可。汉字也是一样,要寻找汉字,直接写在正则表达式里面就可以了。
1.1.1 元字符
但是有些特殊的字符,术语叫 metacharacters(元字符)。
它们出现在正则表达式字符串中,不是表示直接匹配他们, 而是表达一些特别的含义。
现在你已经知道几个很有用的元字符了,如\b,.,,还有\d.正则表达式里还有更多的元字符,比如\s匹配任意的空白符,包括空格,制表符(Tab),换行符,中文全角空格等。\w匹配字母或数字或下划线或汉字等。
下面来看看更多的例子:
\ba\w\b匹配以字母a开头的单词——先是某个单词开始处(\b),然后是字母a,然后是任意数量的字母或数字(\w*),最后是单词结束处(\b)。
\d+匹配1个或更多连续的数字。这里的+是和类似的元字符,不同的是匹配重复任意次(可能是0次),而+则匹配重复1次或更多次。
\b\w{6}\b 匹配刚好6个字符的单词。
代码/语法 | 说明 |
---|---|
. | 匹配除换行符以外的任意字符 |
\w | 匹配字母或数字或下划线或汉字 a1啊_ |
\s | 匹配任意的空白符 |
\d | 匹配数字 123 |
\b | 匹配单词的开始或结束 |
^ | 匹配字符串的开始 |
$ | 匹配字符串的结束 |
元字符(和数字6在同一个键位上的符号)和$都匹配一个位置,这和\b有点类似。^匹配你要用来查找的字符串的开头,$匹配结尾。这两个代码在验证输入的内容时非常有用,比如一个网站如果要求你填写的QQ号必须为5位到12位数字时,可以使用:\d{5,12}
。这里的
5
,
12
和前面介绍过的
2
是类似的,只不过
2
匹配只能不多不少重复
2
次,
5
,
12
则是重复的次数不能少于
5
次,不能多于
12
次,否则都不匹配。因为使用
了
和
。 这里的{5,12}和前面介绍过的{2}是类似的,只不过{2}匹配只能不多不少重复2次,{5,12}则是重复的次数不能少于5次,不能多于12次,否则都不匹配。 因为使用了^和
。这里的5,12和前面介绍过的2是类似的,只不过2匹配只能不多不少重复2次,5,12则是重复的次数不能少于5次,不能多于12次,否则都不匹配。因为使用了和,所以输入的整个字符串都要用来和\d{5,12}来匹配,也就是说整个输入必须是5到12个数字,因此如果输入的QQ号能匹配这个正则表达式的话,那就符合要求了。
和忽略大小写的选项类似,有些正则表达式处理工具还有一个处理多行的选项。如果选中了这个选项,^和$的意义就变成了匹配行的开始处和结束处。
1.1.2 字符转义
如果你想查找元字符本身的话,比如你查找.,或者*,就出现了问题:你没办法指定它们,因为它们会被解释成别的意思。这时你就得使用\来取消这些字符的特殊意义。因此,你应该使用.和*。当然,要查找\本身,你也得用\.
例如:deerchao.net匹配deerchao.net,C:\Windows匹配C:\Windows。
1.1.3 重复
我们已经看过了前面的*,+,{2},{5,12}这几个匹配重复的方式了。下面是正则表达式中所有的限定符(指定数量的代码,例如*,{5,12}等):
代码/语法 | 说明 |
---|---|
* | 重复零次或更多次,相当于{0,n} |
+ | 重复一次或更多次,相当于{1,n} |
? | 重复零次或一次,相当于{0,1} |
{n} | 重复n次 |
{n,} | 重复n次或更多次 |
{n,m} | 重复n到m次 |
下面是一些使用重复的例子:
Windows\d+匹配Windows后面跟1个或更多数字
^\w+匹配一行的第一个单词(或整个字符串的第一个单词,具体匹配哪个意思得看选项设置)
1.1.4 字符类
要想查找数字,字母或数字,空白是很简单的,因为已经有了对应这些字符集合的元字符,但是如果你想匹配没有预定义元字符的字符集合(比如元音字母a,e,i,o,u),应该怎么办?
很简单,你只需要在方括号里列出它们就行了,像[aeiou]就匹配任何一个英文元音字母,[.?!]匹配标点符号(.或?或!)。
我们也可以轻松地指定一个字符范围,像[0-9]代表的含意与\d就是完全一致的:一位数字;同理[a-z0-9A-Z_]也完全等同于\w(如果只考虑英文的话)。
下面是一个更复杂的表达式:(?0\d{2}[)-]?\d{8}。
注意:(
和)
也是元字符,后面的分组节里会提到,所以在这里需要使用转义。
这个表达式可以匹配几种格式的电话号码,像(010)88886666,或022-22334455,或02912345678等。我们对它进行一些分析吧:首先是一个转义字符(,它能出现0次或1次(?),然后是一个0,后面跟着2个数字(\d{2}),然后是)或-或空格中的一个,它出现1次或不出现(?),最后是8个数字(\d{8})。
1.1.5 分枝条件
不幸的是,刚才那个表达式也能匹配010)12345678或(022-87654321这样的不正确
的格式。要解决这个问题,我们需要用到分枝条件。正则表达式里的分枝条件指的是有几种规则,如果满足其中任意一种规则都应该当成匹配,具体方法是用|把不同的规则分隔开。听不明白?没关系,看例子:
0\d{2}-\d{8}|0\d{3}-\d{7}这个表达式能匹配两种以连字号分隔的电话号码:一种是三位区号,8位本地号(如010-12345678),一种是4位区号,7位本地号(0376-2233445)。
(0\d{2})[- ]?\d{8}|0\d{2}[- ]?\d{8}这个表达式匹配3位区号的电话号码,其中区号可以用小括号括起来,也可以不用,区号与本地号间可以用连字号或空格间隔,也可以没有间隔。你可以试试用分枝条件把这个表达式扩展成也支持4位区号的。
\d{5}-\d{4}|\d{5}这个表达式用于匹配美国的邮政编码。美国邮编的规则是5位数字,或者用连字号间隔的9位数字。之所以要给出这个例子是因为它能说明一个问题:使用分枝条件时,要注意各个条件的顺序。如果你把它改成\d{5}|\d{5}-\d{4}的话,那么就只会匹配5位的邮编(以及9位邮编的前5位)。原因是匹配分枝条件时,将会从左到右地测试每个条件,如果满足了某个分枝的话,就不会去再管其它的条件了。
1.1.6 分组
我们已经提到了怎么重复单个字符(直接在字符后面加上限定符就行了);但如果想要重复多个字符又该怎么办?你可以用小括号来指定子表达式(也叫做分组),然后你就可以指定这个子表达式的重复次数了,你也可以对子表达式进行其它一些操作(后面会有介绍)。
(\d{1,3}.){3}\d{1,3}是一个简单的IP地址匹配表达式。要理解这个表达式,请按下列顺序分析它:\d{1,3}匹配1到3位的数字,(\d{1,3}.){3}匹配三位数字加上一个英文句号(这个整体也就是这个分组)重复3次,最后再加上一个一到三位的数字(\d{1,3})。
IP地址中每个数字都不能大于255. 经常有人问我, 01.02.03.04 这样前面带有0的数字, 是不是正确的IP地址呢? 答案是: 是的, IP 地址里的数字可以包含有前导 0 (leading zeroes).
不幸的是,它也将匹配256.300.888.999这种不可能存在的IP地址。如果能使用算术比较的话,或许能简单地解决这个问题,但是正则表达式中并不提供关于数学的任何功能,所以只能使用冗长的分组,选择,字符类来描述一个正确的IP地址:((2[0-4]\d|25[0-5]|[01]?\d\d?).){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)。
理解这个表达式的关键是理解2[0-4]\d|25[0-5]|[01]?\d\d?,这里我就不细说了,你自己应该能分析得出来它的意义。
1.1.7 反义
有时需要查找不属于某个能简单定义的字符类的字符。比如想查找除了数字以外,其它任意字符都行的情况,这时需要用到反义:
代码/语法 | 说明 |
---|---|
\W | 匹配任意不是字母,数字,下划线,汉字的字符 |
\S | 匹配任意不是空白符的字符 |
\D | 匹配任意非数字的字符 |
\B | 匹配不是单词开头或结束的位置 |
[^x] | 匹配除了x以外的任意字符 |
[^aeiou] | 匹配除了aeiou这几个字母以外的任意字符 |
例子:\S+匹配不包含空白符的字符串。
<a[^>]+>匹配用尖括号括起来的以a开头的字符串。
1.1.8 处理选项
上面介绍了几个选项如忽略大小写,处理多行等,这些选项能用来改变处理正则表达式的方式。下面是常用的正则表达式选项:
IgnoreCase(忽略大小写)
:匹配时不区分大小写。
Multiline(多行模式)
:更改^和
的含义,使它们分别在任意一行的行首和行尾匹配,而不仅仅在整个字符串的开头和结尾匹配。
(
在此模式下,
的含义,使它们分别在任意一行的行首和行尾匹配,而不仅仅在整个字符串的开头和结尾匹配。(在此模式下,
的含义,使它们分别在任意一行的行首和行尾匹配,而不仅仅在整个字符串的开头和结尾匹配。(在此模式下,的精确含意是:匹配\n之前的位置以及字符串结束前的位置。)
Singleline(单行模式)
:更改.的含义,使它与每一个字符匹配(包括换行符\n)。
IgnorePatternWhitespace(忽略空白)
:忽略表达式中的非转义空白并启用由#标记的注释。
ExplicitCapture(显式捕获)
:仅捕获已被显式命名的组。
一个经常被问到的问题是:是不是只能同时使用多行模式和单行模式中的一种?答案是:不是。这两个选项之间没有任何关系,除了它们的名字比较相似(以至于让人感到疑惑)以外。
1.1.9 一些常见的正则匹配
校验数字
数字:[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)$
校验字符
汉字:[\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}$
可以输入含有^%&',;=?KaTeX parse error: Expected group after '^' at position 8: \"等字符:[^̲%&',;=?\x22]+
禁止输入含有的字符:[]+
特殊校验
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[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-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}))KaTeX parse error: Undefined control sequence: \d at position 39: …校验位,可能为数字或字符X:(\̲d̲{15})|(\d{18}KaTeX parse error: Undefined control sequence: \d at position 4: )|(\̲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*KaTeX parse error: Undefined control sequence: \s at position 3: 或(\̲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}