正则表达式

调试方式

首先,我们可以利用文本编辑器自带的搜索功能测试自己写的正则表达式,atom、vscode等等都支持正则搜索;以atom作为例子,Ctrl/Cmd + F开启搜索框,并且点击右边正则和区分大小写的开关即可,上图:

然后在搜索框输入正则表达式就能看到是否正确匹配需要的字符串了,因此这里先给出一个后面要用到的调试文本,以供后面描述内容的调试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
abcdefghijklmnopqurtuvwxyz
ABCDEFGHIJKLMNOPQRSTUVWXYZ
1234567890

Ha HaHa HaHaHa

cat
mat
pat
bat
·
tiny-calf.com

321-555-4321
123.555.1234
123*555*1234
800.555.1234
900.555.1234

Mr. Schafer
Mr T
Mr
Mr Smith
Ms Davis
Mrs. Robinson

转义符

  • .在正则中的意义是所有字符,包括空格不包括回车;所以在搜索框输入.时所有文本都会被选中;
    输入.测试本条
  • 那么我们只想匹配.这个字符本身怎么办,那就只要在它之前加上转义符,即\
    输入\.测试本条
  • 如果要匹配字符\则需要转义它自己;
    输入\\测试本条
  • 要匹配示例文本中的网址,输入tiny-calf\.com测试本条
  • 正则中类似.的特殊字符字符总共有这几个,如果要匹配字符本身则都需要转义符:.[]{}()\^$|?*+,这几个特殊字符后面也会一一说明;
    本条自行测试

转义符+特殊字母

以下几个特殊的字母在前面加上转义符以后在正则中有特殊含义,我们逐一看看:

  • \d表示匹配数字 (0-9);d表示Digit;而\D则表示非数字;
    输入 \d\D测试本条
  • \w\W也同理,w代表Word,也就是普通字符,包括a-z A-Z 0-9 _;则\w匹配普通字符,\W匹配非普通字符;
    输入 \w\W测试本条
  • \s\S也同理,s代表Space,这里的Space包括 空格、tab和回车空行;
    输入 \s\S测试本条

字符串匹配以及[]的应用

以上只讲了最基础的单个字符的匹配,把他们组合起来就是我们常用的字符串匹配了,例如示例中的电话号码:

1
2
3
4
5
321-555-4321
123.555.1234
123*555*1234
800.555.1234
900.555.1234

  • 匹配所有电话号码:
    数字位是\d,连接符号需要匹配所有字符所以可以用.:
    输入\d\d\d.\d\d\d.\d\d\d\d测试本条
  • 只匹配连接符号是-.的电话号码:
    我们需要用到特殊字符[],它代表一个单选,表示该位置可以是[]中内容的其中一个;这里连接位就可以用它表示:
    输入\d\d\d[.-]\d\d\d[.-]\d\d\d\d测试本条;
  • 在上面一条的基础上,匹配开头是800或者900的电话号码:
    依然还是用[]实现,第一位数字有89两个选择,后面的00直接用普通字符表示即可;
    输入[89]00[.-]\d\d\d[.-]\d\d\d\d测试本条
  • []中可以用一个特殊含义的字符-表示数字或字符的范围,而不用把所有数字和字符都写出来,比如[0-9a-zA-Z]表示该位可以是所有数字和字母,所以上面一条也可以用这个实现:
    输入[8-9]00[.-]\d\d\d[.-]\d\d\d\d测试本条

还有一条我们用另一个文本来测试:

1
2
3
4
cat
mat
pat
bat

  • 匹配开头不是b,后面两位是at的单词:
    这里会用到了[]中的另一个特殊字符^表示“非”在括号内最前面加上即可:
    输入[^b]at测试本条

引用符号{}+?*

{}+?*都用于将某一位的匹配规则引用到后面的N位中,因此他们都在某匹配规则的后方;
{}表示让某一位的匹配重复应用到后面的确切的N位中,还是拿电话号码的文本作为例子:

1
2
3
4
5
321-555-4321
123.555.1234
123*555*1234
800.555.1234
900.555.1234

  • 上一节用\d\d\d表示三位数字,就可以用{}来简化;
    输入\d{3}.\d{3}.\d{4}测试本条

+?*用于表示不确定数量的引用,关于这些我们用另一个更合适的例子:

1
2
3
Mr Schafer
Mr T
Mr

我们来匹配Mr开头的所有名字:
开头一定是Mr\s,注意有一个空格;后面要匹配所有字母,我们先写一个[a-zA-Z];然后我们要把[a-zA-Z]这个规则重复多次,分别使用+?*来看看效果

  • 在正则后面增加++表示至少一个,所以效果应该是只有Mr这行没被选中;
    输入Mr\s[a-zA-Z]+测试本条
  • 在正则后面增加??表示一个或没有,此时效果应该是Mr SMr TMr被选中了,为了匹配完整的一行字符串,我们在后面再加一个$表示匹配结束了,后面不应该有其他字符,此时现在我们应该看到只有Mr T被选中;
    输入Mr\s[a-zA-Z]?$测试本条
  • 在正则后面增加**表示随便多少位,此时效果应该是所有行都被选中了
    输入Mr\s[a-zA-Z]*测试本条

集合符号()的应用

集合符号的作用之一是方便引用符号{}+?*的使用,因为正常引用符号只能针对一位匹配规则进行引用,使用集合符号后,可以对多位的匹配规则进行引用,以下我们用一个网址的例子:

1
2
3
4
https://www.google.com
http://coreyms.com
https://youtube.com
https://www.nasa.gov

  • 匹配所有url:
    这里的www有的有,有的没有,按照上面的经验我们应该要用到?,这里我们可以把www用集合符号括起来,对这个集合使用?
    输入https?://(www\.)?(\w+)(\.\w+)测试本条

集合符号还有一个作用就是在正则的替换规则中,可以用数字指定某一个集合;

  • 替换字符串,只保留一级二级域名:
    从上一条来看,一级二级域名分别处于第二个集合和第三个集合,那么此时我们只要在替换框里面输入$2$3,点替换所有,就可以实现目标了;
    replace框输入$2$3并点击ReplaceAll测试本条

集合符号中还可以使用特殊符号|来表示选择,比如我们想匹配上面的所有名字:

1
2
3
4
5
6
Mr. Schafer
Mr T
Mr
Mr Smith
Ms Davis
Mrs. Robinson

  • 匹配所有名字:
    输入 M(r|s|rs)\.?\s[A-Z]\w*测试本条

^$

^$分别匹配行的开头和结尾,在正则中我们可以把“行”看作以“回车”分割的字符串;所以当我们输入^Ha的时候,只匹配了Ha HaHa HaHaHa这行的最前面的Ha;而当我们输入Ha$或者HaHa$时则匹配了末尾的字符串

正则匹配邮箱典型练习

先来一个邮箱列表方便调试:

1
2
3
CoreyMSchafer@gmail.com
corey.schafer@university.edu
corey-321-schafer@my-work.net

这里我提供一些答案,可以尝试读懂并测试他们的区别:

1
2
3
4
[a-zA-Z]+@[a-zA-Z]+\.com
[a-zA-Z.]+@[a-zA-Z]+\.(com|edu)
[a-zA-Z0-9.-]+@[a-zA-Z.-]+\.(com|edu|net)
[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+

正则表达式查询表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
.       - 所有字符(包括空格不包括回车)
\d - 数字 (0-9) d表示Digit
\D - 非数字
\w - 字符 (a-z, A-Z, 0-9, _) w表示Word
\W - 非字符
\s - 空格 (空格、tab和回车) s表示Space
\S - 非空格

^ - 匹配字符串的开头
$ - 匹配字符串的结尾

[] - 匹配在某范围内的一个字符
[^ ] - 匹配不是该范围中的一个字符
| - 或
( ) - 集合

* - 引用匹配规则 0次 或 1次 或 多次
+ - 引用匹配规则 1次 或 多次
? - 引用匹配规则 0次 或 1
{3} - 引用匹配规则 3
{3,4} - 引用匹配规则 3次或4