正则匹配

正则引擎

正则的引擎大致可分为两类:DFA和NFA

  1. DFA (Deterministic finite automaton) 确定型有穷自动机
  2. NFA (Non-deterministic finite automaton) 非确定型有穷自动机,大部分都是NFA

这里的“确定型”指,对于某个确定字符的输入,这台机器的状态会确定地从a跳到b,“非确定型”指,对于某个确定字符的输入,这台机器可能有好几种状态的跳法;这里的“有穷”指,状态是有限的,可以在有限的步数内确定某个字符串是否满足条件;这里的“自动机”指,一旦这台机器的规则设定完成,就可以自行判断了,不要人看。

DFA引擎不需要进行回溯,所以匹配效率一般情况下要高,但是它并不支持捕获组,于是也就不支持反向引用和$这种形式的引用,也不支持环视(Lookaround)、非贪婪模式等一些NFA引擎特有的特性。


声明方式

  • 使用构造函数
var reg = new RegExp("<style[^>]*>([\\s\\S]*)</style>","g")

此时其中\视为字符串\,如需使用其他功能需要转义\\

  • 直接声明
var reg = /<style[^>]*>([\s\S]*)<\/style>/g

此时其中字符串/需要\/进行转义


字符和位置

  • 如果一个子正则表达式匹配到的是字符,而不是位置,而且会被保存到最终的结果中,那个这个子表达式就是占有字符的,比如/ha/(匹配ha)就是占有字符的;
  • 如果一个子正则匹配的是位置,而不是字符,或者匹配到的内容不保存在结果中(其实也可以看做一个位置),那么这个子表达式是零宽度的,比如/read(?=ing)/(匹配reading,但是只将read放入结果中),其中的(?=ing)就是零宽度的,它本质代表一个位置。

占有字符是互斥的,零宽度是非互斥的。一个字符,同一时间只能由一个子表达式匹配,而一个位置,却可以同时由多个零宽度的子表达式匹配。举个栗子,/aa/是匹配不了a的,这个字符串中的a只能由正则的第一个a字符匹配,而不能同时由第二个a匹配;但是位置是可以多个匹配的,比如/\b\b?=a/是可以匹配a的,虽然正则表达式里有3个零宽度的子表达式,是可以同时匹配位置0的。

修饰符

  • i 忽视大小写。
  • g 全局匹配。
    不启用全局匹配时,match方法返回的数组第一项为第一个匹配内容,后续为各个捕获组
    启用全局匹配时会返回所有匹配内容,但不包括捕获组
  • m 将^$变为匹配单行的开始和结尾。(并非有m时才能多行匹配)
  • s (ES2018新增修饰符)启用dotALl模式,允许.匹配一切字符

简单元字符

  • ^ 脱字符,表示文本的开始(有m时则为行初)
  • $ 表示文本的结束(有m时则为行末)

一般来说,反斜杠把元字符还原为普通字符,但是有一些普通字符,带反斜杠后反而变成了元字符。

  • \b 匹配一个单词边界(boundary,匹配一个位置,该位置前后不全是\w能描述的字符且不是中文。通常匹配单词和空格之间的位置,包括开头结尾)
  • \B 匹配一个非单词边界
  • \d 匹配一个数字字符(digit)
  • \D 匹配一个非数字字符
  • \s 匹配一个空白字符(space,空格和\f\n\r\t\v的超集)
    • 其中\f是换页符,\n是换行符,\r是回车符,\t是水平制表符,\v是垂直制表符,除空格和\n外均为不可打印字符,因此可以认为匹配[\n| ]
  • \S 匹配一个非空白字符
  • \w 匹配一个字母或者一个数字或者一个下划线(word)
  • \W 匹配一个字母、数字和下划线之外的字符
  • .可以匹配换行符之外的任意单个字符。
    (.|\n)[\b\B][\d\D][\s\S][\w\W]是等价的。

量词 (它重复紧贴在它前面的某个集合。)

  • ? 重复零次或者一次
  • + 重复一次或者多次,也就是至少一次
  • * 重复零次或者多次,也就是任意次数
  • {n} 重复n次
  • {n,} 重复n次或者更多次
  • {n,m} 重复n次到m次

转义

任何在正则表达式中有作用的字符都建议转义,哪怕有些情况下不转义也能正确,比如[]中的圆括号、^符号等。

优先级问题

优先级从高到低是:

  1. 转义 \
  2. 括号(圆括号和方括号)(), (?:), (?=), []
  3. 字符和位置
  4. 竖线 |

贪婪模式与非贪婪模式

  • 紧贴在量词后的?可以开启非贪婪模式
    不带问号的限定符也称匹配优先量词,带问号的限定符也称忽略匹配优先量词。

字符组与分歧

  • []中的字符集合只是所有的可选项,最终它只能匹配一个字符。
    此时$ & @ ()等元字符只视为普通字符,不需要转义。
  • ^ 在字符组中表示取反,不再是文本开始的位置了。
  • - 连字符,匹配范围在它的左边字符和右边字符之间(如[0-9])。只有字母和数字可以用连字符。

分歧 :
[(ab)(cd)]并不会用来匹配字符串“ab”或“cd”,而是匹配a、b、c、d、(、)这6个字符中的任一个,也就是想表达“匹配字符串ab或者cd”这样的需求不能这么做,要这么写ab|cd

捕获组与非捕获组

()将其中的字符集合打包成一个集合,供量词操作。且其内容可以被捕获。

  • 正则内捕获
    使用\数字的形式,从\1开始,分别对应前面的圆括号捕获的内容 (从左向右,从外向内)。这种捕获的引用也叫反向引用
'<App>hello regex</App><p>A</p><p>hello regex</p>'
.match(/<((A|a)pp)>(hello regex)+<\/\1><p>\2<\/p><p>\3<\/p>/);
  • 正则外捕获
    RegExp是构造正则的构造函数。
    RegExp会在我们调用了正则表达式的方法后, 自动将最近一次的结果保存在里面,它的实例属性$数字会显示对应的引用。
const r = /^(\d{4})-(\d{1,2})-(\d{1,2})$/
r.exec('2019-10-08')
 
console.log(RegExp.$1)  // 2019
console.log(RegExp.$2)  // 10
console.log(RegExp.$3)  // 08

另外在replace方法中也支持引用

'hello **regex**'.replace(/\*{2}(.*)\*{2}/, '<strong>$1</strong>');
// "hello <strong>regex</strong>"
  • 非捕获组
    只要在圆括号内最前面加上?:标识,即不会被捕获,可以节省性能

捕获命名 (ES2018的新特性)

  • 在捕获组内部最前面加上?<key>,它就被命名了。使用\k<key>语法就可以引用已经命名的捕获组。
let res = '<App>hello regex</App>'.match(/<(?<tag>[a-zA-Z]+)>.*<\/\k<tag>>/);
res.groups.tag // App

零宽断言

注意,2023年4月为止 safari不支持零宽断言!!!请勿在微信web开发中使用。

零宽断言简称断言,别名环视、巡视,用于匹配一个位置而非字符。断言内容本身需处于括号内,但不会被捕获为捕获组

  • 肯定先行断言 : 为紧贴在它前面的规则服务。如x(?=y)匹配后面有y的x
'CoffeeScript JavaScript javascript'.match(/\b\w{4}(?=Script\b)\w/);
// ['JavaS', index: 13, input: 'CoffeeScript JavaScript javascript', groups: undefined]
  • 肯定后行断言 : 如(?<=y)x匹配前面有y的x
  • 否定先行断言 : 如x(?!y)匹配后面不是y的x
  • 否定后行断言 : 如(?<!y)x匹配前面不是y的x

方法

正则方法
  • test
    返回true/false
  • exec
    如匹配成功,返回数组第一项为第一个匹配的字串,之后为各捕获组的反向引用
    如匹配失败,则返回 null。
字符串方法
  • match
    如匹配成功且无修饰符g,同exec
    如匹配成功且有修饰符g,返回数组各项依次为匹配的各字符串,不返回捕获组
    如匹配失败,则返回 null。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,142评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,298评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,068评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,081评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,099评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,071评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,990评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,832评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,274评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,488评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,649评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,378评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,979评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,625评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,643评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,545评论 2 352

推荐阅读更多精彩内容