弄懂正则表达式
一、什么是正则表达式
正则表达式(英语:Regular Expression,在代码中常简写为regex、regexp或RE),又称正规表示式、正规表示法、正规表达式、规则表达式、常规表示法,是计算机科学的一个概念。正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串。在很多文本编辑器里,正则表达式通常被用来检索、替换那些匹配某个模式的文本。【摘】
二、本文中使用工具
本文中的所有例子在 Atom 中进行实验通过,Atom 默认大小写不敏感。
三、匹配单个字符
1. 匹配固定单个字符
所有的单个大小字母、数字及特殊字符,都是一个正则表达式。它们只能匹配单个字符,且这个字符与它本身相同。
【注】上面表达式“l”,可以匹配出 ball, wall,并不是一个“l”一次匹配出了“ll”,而是匹配了单个字符“l”两次。如果用“ll”去匹配,效果如下图。这种情况下需要字符排列顺序与表达式完全相同并相应位置上的字符也与对应字符相同的字符串。这种匹配方式的灵活度最小,只能匹配与它完全相同的字符,也称为“全字匹配”。
2. 匹配任意单个字符
“.” 可以匹配任意的单个字符、字母、数字及其本身。
可以看出:ab 为全字匹配,后面的 “.”可以匹配任意单个字符(也可以包含其本身)。
3. 匹配 “.” 元字符
如果,我们只想匹配 “.” 这个单个字符,也就是其本身。可以通过 “\.” 来对它转义。
4. 匹配字符组
1) 字符组的基本语法
“.” 太好用了,可以匹配几乎所有的单个字符。有时候,我们只希望匹配有限个字符中的某一个,可以使用字符组。
上面,中括号 “[cd.]” 是特殊标记,用以划定属于组内的字符的界限,它所代表的含义是:匹配 “c” 或者 “d” 或者 “.”。
2)字符组中使用字符区间
字符组中可以使用字符区间,其语法是“起始字符-结束字符”。
上面匹配阿拉伯数字时,可以使用 “[1-2]” 来替换 “[1,2]” 。
3)反义字符组
如果现在需要匹配除了某些字符以外的其他字符,可以使用反义字符组,其语法是 “[^字符集合]” 。
5. 匹配特殊字符
1)匹配元字符
所谓元字符就是在正则表达式中具有特殊含义的字符。例:“.” 用来匹配任意单个字符,“\” 叫转义符,还有 “[” 和 “]” 等。
2)匹配空字符
在正则表达式中,常用的三类空白字符如下表。
元字符 | 匹配描述 |
\r | 回车 |
\n | 换行 |
\t | Tab 键 |
\f | 换页 |
\v | 垂直 Tab |
3)匹配特定字符类型
匹配数字类型:
元字符 | 匹配描述 |
\d | 所有单个数字,与 [0-9] 相同 |
\D | 所有非数字,与 [^0-9] 相同 |
匹配字母、数字、下划线:
元字符 | 匹配描述 |
\w | 所有单个大小写字母、数字、下划线,与 [a-zA-z0-9_] 相同 |
\W | 所有单个非大小写字母、数字、下划线,与 [a-zA-z0-9_] 相同 |
匹配空字符:
元字符 | 匹配描述 |
\s | 所有单个空字符,与 [\f\n\r\t\v]相同 |
\S | 所有单个非空字符,与 [\f\n\r\t\v]相同 |
四、匹配多个字符
上面讲到都是匹配单个字符,如果需要匹配一个很长的字符串,而且字符串都比较复杂时,那么一个表达式多么复杂。
1. 匹配一个或多个
可以在 单个字符、字符组、特定字符类型后面加 “+”,来表示匹配一个或多个字符组的字符串。
2. 匹配零个或多个字符
可以在 单个字符、字符组、特定字符类型后面加 “*”,来表示匹配一个或多个字符组的字符串。
3. 匹配零个或一个字符串
正则表达式中,使用 “?” 来匹配零个或一个字符。
4. 匹配指定数目字符
从上面可以出来,“?”、“+”、“*”这三个元字符解决了很多问题,但仍有缺陷,会匹配尽可能多的数字,也就是没办法指定匹配多少个字符。
1)匹配固定数目的字符
正则表达式中,可以在单个字符、字符组、特定字符类型后面加 “{数字}”, 来表示匹配零个或者多个字符组成的字符串。
2)匹配区间以内数目的字符
正则表达式中,使用 “{最小数目,最大数目}” 的语法来实现。
【注】发现一个问题,1234 被当成 123 和 4 进行匹配了。在后面将会讲到如何不让它被匹配。有两种特例:
- 最小数目为 0 时,即 “{0,1}”,相当于 “?”
- 如果不限制最大数目,可以将最打数目设为空,即 “{1,}”,相当于 “+”;而 “{0,}”,相当于 “*”
5. 贪婪匹配和惰性匹配
1)概述
- 贪婪匹配:会匹配尽可能多的字符。首先看整个字符串,如果不匹配,对字符串进行收缩;遇到可能匹配的文本,停止收缩,对文本进行扩展,当发现匹配的文本时,它不着急将该匹配保存到匹配集合中,而是对文本继续扩展,直到无法继续匹配或扩展完整个字符串,然后将前面最后一个符合匹配的文本保存起来到匹配集合中。
- 惰性匹配:会匹配尽可能少的字符。它从第一个字符开始找,一旦符合条件,立刻保存到匹配集合中,然后继续进行查找。
现在我们希望匹配出 “<a>apples</a>” 和 “<a>bears</a>” ,但是用表达式 “<a>.*</a>” 效果不是那么满意。解决的办法就是采用惰性匹配。
贪婪匹配 | 惰性匹配 | 匹配描述 |
? | ?? | 匹配0个或1个 |
+ | +? | 匹配1个或多个 |
* | *? | 匹配0个或多个 |
{n} | {n}? | 匹配n个 |
{n,m} | {n,m}? | 匹配n个或m个 |
{n,} | {n,}? | 匹配n个或多个 |
2)比较
贪婪模式
惰性模式
两者对比发现,惰性模式只匹配了满足0个的条件,就将其保存到匹配结果集,贪婪模式这尽可能多的匹配了。
五、匹配边界
1. 匹配单词边界
正则表达式中,可在字符前加 “\b”,来匹配其后面的字符位于字符串首位的字符。
正则表达式,可以在字符后加 “\b”,来匹配器前面的字符位于字符串末位的字符。
此时 “letter” 就无法匹配到。
2. 边界及其相对性
1)边界的定义
通常情况下,以空格、段落首行、段落末尾、逗号、句号等符号作为边界。当然,分隔符 “-” 也可以作为边界。
2)边界的相对性
- 当对一个普通字符,设定边界的时候,它的边界是诸如空格、分隔符、逗号、句号。
- 当对一个边界,它的边界是普通字符。
3. 匹配非单词边界
同之前匹配特定类型字符有些相似,有了 “\b”,自然有 “\B”,它用来匹配不在边界的字符。
4. 匹配文本边界
1)匹配文本首
在正则表达式中,可以在 匹配模式 的第一个字符前添加 “^”,以匹配满足模式且位于全部文本之首的字符串。
过程:假设不存在“^”,进行一个正常匹配,将所有匹配的文本保存到匹配集合中;在匹配集合中寻找位于所搜索的文本首位的匹配;从匹配集合中删除其他匹配,仅保留匹配。
2)匹配文本末
在正则表达式中,可以在匹配模式的最后一个字符后添加 “$”,以匹配满足模式且位于全部文本之末的字符串。
六、匹配子模式
之前介绍的所有匹配模式(如 “+”、“*”、“{n,m}”),都是针对于某种单个字符。
1. 子模式
在正则表达式中,可以使用 “(” 和 “)” 将模式中的子字符串括起来,以形成一个子模式。将子模式视为一个整体时,那它就相当于一个单个字符。
2. “或” 匹配
在正则表达式中,可以使用 “|” 将一个表达式拆分成两部分 “reg1|reg2”,及匹配所有符号表达式 reg1 的文本或者符号表达式 reg2 的文本。
3. 子模式中使用 “或” 匹配
4. 嵌套子模式
子模式可以继续嵌套子模式,产生更加功能强大的匹配能力。
七、后向引用
1. 理解后向引用
正则表达式中,使用 “\数字” 来进行后向引用,数字表示这里引用的是前面的第几个子模式。
2. 常见应用
匹配有效的HTML标记
总结
这篇随笔主要是将自己学习正则表达式的过程记录下来,方便日后查看,希望对大家也有所帮助。