- Published on
正则表达式速记口诀
- Authors
- Name
- 林晓东
- @xiaodong5959
这是一个正则的助记口诀/顺口溜,让我们用30分钟时间来轻松背下难记的正则
欢迎通过issue提交更好的口诀或者补充未提到的正则表达式
首先先奉上口诀:
从前有个傻大三,
哇塞,日子过得特别难
\w\s\r\z\d\t\b\n
人傻人穷只有捡破烂
做梦都想变成大富豪,就不用再出来捡破烂
\W\S\D\B
每天哼着歌儿出去捡破烂
两手叉着腰,左手捡了右手又捡
a|b
你问他捡到钱没
?
左手回答得还行,右手被问得头冒金星
+
*
只有装进袋子把数字标
{n}
关上门来把金银财宝往屋里搬
[abc]
脑袋儿被门夹了不知道啥东西要选
[^abc]
钢镚儿一碗,铁镚儿一碗
(abc)
没问题的打个标记,好知道有好多钱
(?<name>)
有问题的放一边,挤破脑袋也还要向前再看一眼
(?=exp)
(?!exp)
(?<=)
(?<!)
剩下的铜钱儿用线串
[a-zA-Z0-9]
一不小心遇到地头蛇,一顿拷问被吓得赶紧溜回家
+?
*?
释义
嘴巴儿尖尖,句句都是钱
尖尖代表^
符号,钱代表$
符号
傻大三这个人一张嘴说话,句句都是以钱收尾
所以我们get到了
正则表达式 | 描述 | 示例 |
---|---|---|
^ | 匹配字符串的开始 | ^acb 匹配以abc开头的字符串 |
$ | 匹配字符串结尾 | abc$ 匹配以abc结尾的字符串 |
哇塞,日子过得特别难.
在正则里面有许多的元字符,这里收集了比较常用的一些,取元字符的来当声母,用来助记这些元字符,当然,我们更明白元字符所对应的英文单词,就无须死背元字符所对应的的内容了.
所以我们get到了一大串的元字符
代码 | 描述 | 对应文字 | 对应单词 |
---|---|---|---|
\w | 匹配一个单词的组成部分,字符,数字,下划线.(是否匹配中文视操作系统和应用环境而定) | 哇 | Word |
\s | 匹配空白符 | 塞 | Space |
\r | 回车 | 日 | Enter |
\z | 字符串结尾(类似$,但不受处理多行选项的影响) | 子 | ? |
过 | 过 | ||
\d | 数字 | 得 | Digital |
\t | tab制表符 | 特 | Tabulator key |
\b | 边界,单词分界位置 | 别 | Boundary |
\n | 换行符 | 难 | Line feed |
. | 点号(相当于句号),在一个段落中,以它结尾,它包括了前的各种符号,但不匹配换行符.因为换行就是新段落了 | . |
做梦都想变成大富豪,就不用再出来捡破烂
变成大富豪,表示元字符变成了大写字母
就不用再出来破烂,表示不再匹配,相当于对以上小写的元字符取反
所以我们get到了
代码 | 描述 |
---|---|
\W | 匹配一个非单词的组成部分,字符,数字,下划线.(是否匹配中文视操作系统和应用环境而定) |
\S | 匹配非空白符 |
\D | 非数字 |
\B | 非边界,单词分界位置 |
两手叉着腰,左手捡了右手又捡
这一表示正则里面的分枝匹配,形如a|b
表示两边或的匹配关系,即可以匹配a
也可以匹配b
傻大三捡垃圾,左边有就左手捡到,右边有,就右手捡起来.
你问他捡到钱没?左手回答得还行,右手被问得头冒金星,只有装进袋子把数字标
问到捡到钱没,这是一个问句,回答应该是是与否,代表0或者1,所以有正则?
匹配0次或者1次
因为他左手刚刚捡到了一块垃圾,所以他傻傻地也知道左手捡到有东西,在数学里面就是用正号+
表示,至少有一个.
被问得头冒金星,他也不知道右手到底有没有捡到有东西了.金星用*
表示,可能没有捡到有,也可能捡到很多
只好数一下装进袋子里面,用数字标上有多少.袋子用{}
表示,数字用n
表示有多少个.得到完整的正则表达式{n}
即表示前面的匹配n
次
于是我们get到的正则的匹配模式
代码 | 描述 |
---|---|
+ | 匹配至少一次 |
* | 匹配0次或者多次 |
? | 匹配零次或者一次 |
{n} | 匹配n次 |
{n,m} | 匹配n到m次 |
{n,} | 匹配n次或者更多次,没有m代表无穷尽 |
关上门来把金银财宝往屋里搬,脑袋儿被门夹了不知道啥东西要选
关上门表示[]
符号,关在里面的金银财宝,都可以往屋里搬,所以表达式[abc]
表示匹配abc
任意一个.
结果傻大三的头^
不小心被门给夹住了,不知道要这些金银财宝了.所以表达式[^abc]
表示匹配不是abc
这些字符的.
钢镚儿一碗,铁镚儿一碗
碗用()
表示,傻大三还是知道对这些垃圾进行分类,也就是正则里面的分组,分组之后,不仅可以用于前面的匹配模式,也可以用于后面的反向引用和零宽匹配及更多的功能.
比如(abc){2}
表示匹配连续的两个abc
即abcabc
没问题的打个标记,好知道有好多钱
傻大三对碗打个标记,以免有疑问?
时才好知道有好多钱,所以有正则表达式形式(?<name>exp)
,打好标记之后,在后续就可以通过这个标记来识别引用了.
比如\b(?<Word>\w+)\b\s+\k<Word>\b
表示匹配连续重复的单词,比如go go
.如果不打标记,默认使用数字来识别,每个分组会自动拥有一个组号,规则是:从左向右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推。所以这个表达式不打标记的写法就是\b(\w+)\b\s+\1\b
有问题的放一边,挤破脑袋也还要向前再看一眼
有问题?
的,有可能是真钢镚,即等号=
表示,有可能不是真钢镚,即非!
表示
放一边,表示只匹配了,但不参与捕获.和前面的^
,$
,\b
一样,是属于零宽断言,它们 本身不匹配任何字符,只是对 "字符串的两头" 或者 "字符之间的缝隙" 附加了一个条件.
于是有正预测先行断言(?=exp)
,表示断言自身出现的位置后面能匹配表达式,比如\b\w+(?=ed\b)
表示匹配以ed
结尾的单词,但不包含ed
;
同理有负预测先行断言(?!exp)
,和上面的意思相反,即不能满足表达式.比如\b\w*e(?!d)\w*\b
表示匹配包含e
的单词,但同时e
后面不能跟着字符d
.它和\b\w*e[^d]\w*\b
的区别是,后者的[^d]
会参与一次匹配,比如它会匹配上e,abc
,因为里面的,
参与了[^d]
的匹配.
挤破脑袋向前<
,前面说的是先行断言,即先匹配上前面的表达式.相反的,挤破脑袋往前面去就变成了后发断言.即有
正预测后发断言(?<=exp)
表示断言自身出现的位置前端能匹配表达式exp
负预测后发断言(?<!exp)
表示断言自身出现的位置前面不匹配表达式exp
零宽断言是先满足匹配其自身表达式后,再获取断言里面的表达式是否满足. 比如(?<=\d{4})\d+(?=\d{4})
去匹配1234567890
,先匹配上\d+
,再判断(?<=\d{4}
和(?=d{4})
,于是最终的匹配结果是56
.
综合以上三条,我们对于正则分组,可以再总结一下
代码 | 描述 |
---|---|
(exp) | 分组匹配,后续可以通过\n 进行反向引用 |
(?<word>exp) | 分组匹配命名,后续可以通过\k<word> 进行反向引用 |
(?:exp) | 只分组,不生成分组编号,也不捕获.相当于只看一眼: 而已 |
(?=exp) | 匹配exp 前面的位置 |
(?!exp) | 匹配后面不是跟的exp 的位置 |
(?<=exp) | 匹配exp 后面的后面 |
(?<!exp) | 匹配前面不是跟的exp 的位置 |
剩下的铜钱儿用线串
用线-
串,表示把铜钱儿都串起来了,就是正则里面的[a-zA-Z0-9]
这种表示方法,表示a
到z
的全部大小写字母和0
到9
的全部数字.
一顿拷问被吓得赶紧溜回家
遇到地头蛇拷问?
,溜回家不再捡垃圾,就是正则里面的遇到?
由默认的贪婪匹配变成了非贪婪(惰性)匹配.
比如对于字符串aabaab
用正则a.*b
会匹配上整个字符串,因为它是贪婪匹配的,里面的.*
会尽可能长的进行匹配.
而a.*?b
则只会匹配aab
.因为对于.*
遇到了?
号,就被变成了非贪婪匹配了.
于是结合前面的匹配模式,我们可以get到
代码 | 描述 |
---|---|
+? | 匹配至少一次,但尽可能少地匹配 |
*? | 匹配0次或者多次,但尽可能少地匹配 |
?? | 匹配零次或者一次,但尽可能少地匹配 |
{n,m}? | 匹配n到m次,但尽可能少地匹配 |
{n,}? | 匹配n次或者更多次,没有m代表无穷尽,但尽可能少地匹配 |