正则表达式的干货分享

一、基本概念:

在我们写页面时,常需要对表单数据如账号、密码、身份证号等进行验证,而最有效、用的最多的就是使用正则表达式来验证。

正则表达式(Regular Expression)是用于描述一组字符串特征的模式,用于匹配特定的字符串。其应用非常广泛,特别是在字符串处理方面,应用如下:

1、验证字符串,即验证给定的字符串或子字符串是否符合指定的特征,可验证邮箱地址等。

2、查找字符串,从给定的文本中查找符号指定特征的字符串,比查找固定字符串更灵活。

3、替换字符串,即查找到符合某特征的字符串后将其替换。

4、提取字符串,即从给定的字符串中提取出符合指定特征的子字符串。

二、检测工具介绍

介绍一个工具RegexBuddy

RegexBuddy

三、结构总体介绍

1、字符字面量:

匹配一个具体字符,包括不用转义的和需要转义的。比如a匹配字符"a",又比如\n匹配换行符,又比如\.匹配小数点。

2、字符组:

匹配一个字符,可以是多种可能之一,比如[0-9],表示匹配一个数字。也有\d的简写形式。另外还有反义字符组,表示可以是除了特定字符之外任何一个字符,比如[^0-9],表示一个非数字字符,也有\D的简写形式。

3、量词:

表示一个字符连续出现,比如a{1,3}表示“a”字符连续出现1到3次。另外还有常见的简写形式,比如a+表示“a”字符连续出现至少一次

4、锚点:

匹配一个位置,而不是字符。比如^匹配字符串的开头,又比如\b匹配单词边界,又比如(?=\d)表示数字前面的位置。

5、分组:

用括号表示一个整体,比如(ab)+,表示"ab"两个字符连续出现多次,也可以使用非捕获分组(?:ab)+

6、分支:

多个子表达式多选一,比如abc|bcd,表达式匹配"abc"或者"bcd"字符子串。

7、反向引用:

比如\2,表示引用第2个分组。

四、结构详细介绍

4.1 字符组

虽然是叫字符组,但只是表示其中一个字符,例如[abc],表示匹配一个字符,它可以是“a”、“b”、“c”之一。

(1)范围表示法:

比如[123456abcdefGHIJKLM],可以写成[1-6a-fG-M]。用连字符-来省略和简写。

要匹配“a”、“-”、“z”这三者中任意一个字符,该怎么做呢?不能写成[a-z],因为其表示小写字符中的任何一个字符。可以写成如下的方式:[-az][az-][a\-z]。即要么放在开头,要么放在结尾,要么转义。总之不会让引擎认为是范围表示法就行。

(2)排除字符组:

某位字符可以是任何东西,但就不能是"a"、"b"、"c",排除字符组是反义字符组的概念。

例如[^abc],表示是一个除"a"、"b"、"c"之外的任意一个字符。字符组的第一位放^(脱字符),表示求反的概念。

(3)常见的简写形式:

\d就是[0-9]。表示是一位数字。记忆方式:其英文是digit(数字)。

\D就是[^0-9]。表示除数字外的任意字符。

\w就是[0-9a-zA-Z_]。表示数字、大小写字母和下划线。记忆方式:w是word的简写,也称单词字符。

\W是[^0-9a-zA-Z_]。非单词字符。

\s是[ \t\v\n\r\f]。表示空白符,包括空格、水平制表符、垂直制表符、换行符、回车符、换页符。记忆方式:s是space character的首字母。

\S是[^ \t\v\n\r\f]。 非空白符。

.就是[^\n\r\u2028\u2029]。通配符,表示几乎任意字符。换行符、回车符、行分隔符和段分隔符除外。记忆方式:想想省略号...中的每个点,都可以理解成占位符,表示任何类似的东西。

如果要匹配任意字符怎么办?可以使用[\d\D]、[\w\W]、[\s\S]和[^]中任何的一个。

4.2 量词

量词也称为重复,表示重复多少次;例如:\d{3}表示连续匹配数字3次,即匹配三个连贯的数字。其中{}是闭区间。

(1)简写形式

{m,} 表示至少出现m次。

{m} 等价于{m,m},表示出现m次。

? 等价于{0,1},表示出现或者不出现。记忆方式:问号表示,有或没有

+ 等价于{1,},表示出现至少一次。

* 等价于{0,},表示出现任意次,有可能不出现。

(2)量词中存在的贪婪匹配和惰性匹配

例如:

贪婪匹配

其中正则\d{2,5},表示数字连续出现2到5次。会匹配2位、3位、4位、5位连续数字。但是其是贪婪的,它会尽可能多的匹配。你能给我6个,我就要5个。你能给我3个,我就要3个。反正只要在能力范围内,越多越好。

而惰性匹配,就是尽可能少的匹配;

惰性匹配

其中\d{2,5}?表示,虽然2到5次都行,当2个就够的时候,就不在往下尝试了。

4.3 锚点

锚点即位置匹配,介绍锚点之前先了解下位置的概念。

(1)什么是位置

位置是相邻字符之间的位置。

位置的概念

(2)如何匹配位置

有8个锚字符可以去匹配位置

^    $    \b    \B    (?=p)    (?!p)  (?<=p) (?<!p)

其中

^和$

^(脱字符)匹配开头,在多行匹配中匹配行开头$(美元符号)匹配结尾,在多行匹配中匹配行结尾。比如,把字符串的开头和结尾用“#”替换。

开头和结尾用#替换

\b和\B

\b是单词边界,具体就是\w\W之间的位置,也包括\w^之间的位置,也包括\w$之间的位置。

例如,将指定字符的边界替换为#

替换边界

\B就是\b的反面的意思,非单词边界。例如在字符串中所有位置中,扣掉\b,剩下的都是\B的。

非单词边界

(?=p) 和 (?!p)

(?=p),学名叫零宽度预测先行断言,其中p是一个子模式,即p前面的位置。例如(?=l),表示'l'字符前面的位置

将'l'前面的位置替换为‘#’

(?!p),学名叫零宽度负预测先行断言,就是(?=p)的反面意思,比如:

将不是‘l’前面的位置替换为‘#’

(3)案例分析

数字的千位分隔符表示法,如把“12345678”,变成“12,345,678”。

思路:找到对应的位置替换为“,”。

1、先弄出最后一个逗号

将后面三位数字的前面的位置替换为','

2、弄出所有逗号

因为逗号出现的位置,要求后面3个数字一组,也就是\d{3}至少出现一次。此时可以使用量词+:

开头部分也被匹配进去了

3、要求匹配的位置不能是开头

使用(?!^)排除开头位置
使用\B也能实现同样效果

(?<=p) 和(?<!p)

注:这两种模式javascript是不支持的,请在RegexBuddy工具中把语言切换到c#模式。

(?<=p) ,学名叫零宽度回顾后发断言,表示p后面的这个位置

(?<=p)表示p后面的位置

(?<!p),学名叫零宽度回顾后发断言,表示不是p后面的位置,或者说是p后面的位置不能匹配;

不能匹配p的后面位置的内容


4.4 多选分支

形式如:(p1|p2|p3),其中p1、p2、p3是子模式,用|(管道符)分隔,表示其中任何之一。

它也是惰性匹配,即找到一个匹配的就不继续尝试查找了。

4.5 括号的作用

a+匹配连续出现的“a”,而要匹配连续出现的“ab”时,需要使用(ab)+

(ab)+的匹配

多选分支结构(p1|p2)中,括号提供了子表达式的所有可能。如:

两种都能匹配

反向引用

在正则里引用之前出现的分组,即反向引用。如:当我们想用正则支持如下三种日期格式时:

匹配三种格式的日期

以上正则虽然能匹配要求的情况,但也匹配了“2019-09/10”这样的数据,如果想要分割符前后一致,需要使用反向引用;

反向引用

其中,\1表示引用之前的那个分组(-|\/|\.)。不管它匹配到什么(比如-),\1都匹配那个同样的具体某个字符。我们知道了\1的含义后,那么\2\3的概念也就理解了,即分别指代第二个和第三个分组

当括号存在嵌套时,以左括号为准,如

括号嵌套

我们可以看看这个正则匹配模式:

第一个字符是数字,比如说1,

第二个字符是数字,比如说2,

第三个字符是数字,比如说3,

接下来的是\1,是第一个分组内容,那么看第一个开括号对应的分组是什么,是123,

接下来的是\2,找到第2个开括号,对应的分组,匹配的内容是1,

接下来的是\3,找到第3个开括号,对应的分组,匹配的内容是23,

最后的是\4,找到第4个开括号,对应的分组,匹配的内容是3。

引用不存在的分组

反向引用,是引用前面的分组,但我们在正则里引用了不存在的分组时,有些语言会报编译错误(引用了不存在的分组),如c#,但有些语言是支持的,如javascript,只是匹配反向引用的字符本身。例如\2,就匹配"\2"。注意"\2"表示对"2"进行了转意。大概如:

\1到\9代表的具体字符

非捕获分组

之前文中出现的分组,都会捕获它们匹配到的数据,以便后续引用,因此也称他们是捕获型分组。如果只要括号最原始的功能,但不会引用它,即,既不在API里引用,也不在正则里反向引用。此时可以使用非捕获分组(?:p),注意和上文中的(?=p)进行区分。

非捕获分组

4.6 回溯法原理

引擎会依次处理各个子表达式或组成元素,遇到需要在两个可能成功的选项进行选择的时候,它会选择其一,同时记住另一个,以备稍后可能的需要。如果正则表达式中余下的部分最终匹配失败,引擎会知道需要回溯到之前做出选择的地方,选择其他的备用分支继续尝试。这样,引擎最终会尝试表达式的所有可能途径(或者是匹配完成之前需要的所有途径)。

形象的说,回溯就像是在道路的每个分岔口留下一小堆面包屑。如果走了死路,就可以照原路返回,直到遇到面包屑标示的尚未尝试过的道路。如果那条路也走不通,你可以继续返回,找到下一堆面包屑,如此重复,直到找到出路,或者走完所有没有尝试过的路。

(1)没有回溯的匹配

假设我们的正则是ab{1,3}c,其可视化形式是

可视化形式

当目标字符串是"abbbc"时,就没有所谓的“回溯”。其匹配过程是

没有回溯的匹配

(2)有回溯的匹配

如果目标字符串是“abbc”,则会存在回溯。

有回溯的匹配

图中第5步有红颜色,表示匹配不成功。此时b{1,3}已经匹配到了2个字符“b”,准备尝试第三个时,结果发现接下来的字符是“c”。那么就认为b{1,3}就已经匹配完毕。然后状态又回到之前的状态(即第6步,与第4步一样),最后再用子表达式c,去匹配字符“c”。当然,此时整个表达式匹配成功了。其中的第6步就是回溯

再举个例子,正则是ab{1,3}bbc

可视化形式

目标字符串是"abbbc",匹配过程是:

有回溯的匹配

其中第7步和第10步是回溯。第7步与第4步一样,此时b{1,3}匹配了两个"b",而第10步与第3步一样,此时b{1,3}只匹配了一个"b",这也是b{1,3}的最终匹配结果。

(3)回溯法总结

回溯法也称试探法,它的基本思想是:从问题的某一种状态(初始状态)出发,搜索从这种状态出发所能达到的所有“状态”,当一条路走到“尽头”的时候(不能再前进),再后退一步或若干

步,从另一种可能“状态”出发,继续搜索,直到所有的“路径”状态都尝试过。这种不断“前进”、不断“回溯”寻找解的方法,就称为“回溯法”。

(4)可能出现回溯的地方

贪婪量词

之前的例子都是贪婪量词相关的。比如b{1,3},因为其是贪婪的,尝试可能的顺序是从多往少的方向去尝试。首先会尝试"bbb",然后再看整个正则是否能匹配。不能匹配时,吐出一个"b",即在"bb"的基础上,再继续尝试。如果还不行,再吐出一个,再试。如果还不行呢?只能说明匹配失败了。

惰性量词

惰性量词就是在贪婪量词后面加个问号,表示尽可能少的匹配。虽然惰性量词不贪,但也会有回溯的现象。比如正则是

惰性量词的回溯
有回溯的匹配

虽然惰性匹配不贪,但是为了整体匹配成,也只能给你多塞点。因此最后\d{1,3}?匹配的字符是"12",是两个数字,而不是一个。

五、实践

(1)试着用正则表达式匹配IP地址;

(2)验证用户密码,要求必须是大、小写字母、数字至少两种的结合;

(3)了解下正则表达式引发的血案,你知道问题出在哪儿吗?   https://juejin.im/post/5b287ea6f265da596d04a324

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容

  • 正则表达式是匹配模式,匹配字符或者匹配位置。 一、字符匹配 1.两种模糊匹配 1.1 横向模糊匹配 一个正则可匹配...
    菜菜的小阿允阅读 1,628评论 0 0
  • 正则表达式学习笔记 一篇记录了学习正则表达式的笔记。 1. 转义字符 在 HTMl 中转义字符以 & 符号开头,分...
    heyi_let阅读 388评论 0 0
  • Python中的正则表达式(re) import rere.match #从开始位置开始匹配,如果开头没有则无re...
    BigJeffWang阅读 7,050评论 0 99
  • 正则表达式有很多流派,也有很多的特性,不同的语言支持度也是不一样的。本篇文章是写Python中的正则表达式的用法的...
    Moscow1147阅读 1,080评论 0 0
  • 从匹配中返回值 Match 对象 成功的匹配总是返回一个 Match 对象, 这个对象通常也被放进 $/ 中, (...
    焉知非鱼阅读 1,775评论 0 1