js正则表达式

正则表达式必知必会

正式表达式基础可阅读菜鸟教程-js正则

匹配过程

匹配字符(str):'acdcabab'
表达式(reg):/ab/g
首先由正式表达式reg的'a'获得控制权,从str的位置1开始重试匹配,匹配到字符串'a'成功,控制权交给reg的b。开始从位置1开始匹配,匹配到字符'c'失败,控制权交还给a。
开始从位置3开始匹配,匹配到字符'd'失败,继续向后位置4匹配到'c'失败。再继续向后位置5匹配到字符'a'成功,控制权交个reg的b,从位置6继续匹配到'b'成功(因为这里/g全局匹配,需要匹配完整个字符串。如果没有g全局匹配,此时匹配结束)。控制权交还给a,继续向后位置7匹配到a成功。控制权再次交给b,继续向后位置8匹配到b成功。已经匹配到最后一个字符,匹配结束。

特别注意,如下:使用变量接收创建的正则表达式,使用该表达式的test方法,匹配成功时会记录当前的下标,下次配时会从该下标开始匹配

let reg = /ab/g;  // reg.lastIndex = 0
// 从下标0开始匹配
reg.test('1234ab222ab'); // true  reg.lastIndex = 6
// 从下标6开始匹配
reg.test('1234ab222ab'); // true  reg.lastIndex = 11
// 从下标11开始匹配
reg.test('1234ab222ab'); // false reg.lastIndex = 0

贪婪模式,惰性模式

  • 贪婪模式:尽可能多匹配,有多少匹配多少
  • 惰性模式:尽可能少匹配,能不匹配就不匹配

在量词后面加上?就变成惰性模式

惰性限定符列表:

语法结构 语义解释
*? 可以重复任意次,但是尽可能重复少的次数。
+? 可以重复1次或者任意多次,但是尽可能重复少的次数,不过最少次数是1。
?? 可以重复0次或1次,但尽可能少重复。
{n,m}? 可以重复n到m此,但尽可能少重复,最少匹配次数是n。
{n,}? 可以重复n次以上,但尽可能少重复,最少匹配n次。

示例:
待匹配字符串: abbbbb
贪婪模式:/ab*/ -> abbbbb (*表示可批量0个或多个,所有这里会匹配尽可能多的b)
惰性模式(量词后加?):/ab*?/ -> a (惰性模式下,尽可能少的匹配,所有这里匹配了0个b)

虽然惰性模式会尽量少匹配,但并不会跳过匹配
例如 'bbba'.match(/b*?a/)会匹配bbba而不是ba,这是因为匹配是从第一个开始匹配,而不会跳过匹配

分组

用一对括号()包裹起来的内容就代表了分组,每一对括号就是一个分组,分组可以分为捕获型分组非捕获型分组,以及正向前瞻型分组反向前瞻型分组

  • 捕获型分组
    捕获型分组会在 比如 match exec这样的函数中以第二项,第三项的形式得到相应分组的结果

顺道说下match exec函数的区别。match是字符串的方法,语法str.match(regexp);exec是正则表达式的方法,语法regexp.exec(str),同时exec的regexp有没有g都无影响。

var str = 'ab12cd34ef'
console.log(str.match(/(\d+)/)) //["12", "12", index: 2, input: "ab12cd34ef", groups: undefined]
console.log(str.match(/(\d+)cd(\d+)/)) //["12cd34", "12", "34", index: 2, input: "ab12cd34ef", groups: undefined]

上面第一个打印的结果中的数组[0]就是就是匹配的结果,数组[1]就是第一个捕获分组的结果,第二个打印的结果中数组[2]就是第二个捕获分组的结果。依次类推,如果还有更多捕获分组,会在数组中以第四项([3]),第五项([4])...的形式返回

  • 非捕获型分组(?:)
    非捕获型分组也就是 有些地方需要用到一对括号,但是又不想让他成为一个捕获型分组也就是不想让这个分组被类似 macth exec 这样的函数所获取到通常在括号内部的前面加上?: 也就是 (?:pattern)这样就变成了一个非捕获型分组
var str = 'ab12cd34ef'
console.log(str.match(/(?:\d+)/)) //["12", index: 2, input: "ab12cd34ef", groups: undefined]
console.log(str.match(/(?:\d+)cd(?:\d+)/)) //["12cd34", index: 2, input: "ab12cd34ef", groups: undefined]

这样,就不会捕获()中所匹配的结果了

  • 正向前瞻型分组(?=)
    正向前瞻(?=表达式)表示后面要有什么
// 匹配.jpg后缀文件名
var str = '123.jpg,456.gif,abc.jpg';
var regexp = /\w+(?=\.jpg)/g; 
console.log(str.match(regexp)); // ["123", "abc"]
  • 反向前瞻型分组(?!)
    反向前瞻(?!表达式)表示后面不能有什么
// 匹配不是.jpg后缀文件名
var str = '123.jpg,456.gif,abc.jpg';
var regexp = /\w+(?=\.(?!jpg))/g; 
console.log(str.match(regexp)); // ["456"]  
// 处理数字的千位分隔符,匹配的位置不可能是开头
var expreg = /(?!^)(?=(\d{3})+$)/g;
'123456789'.replace(expreg,','); // "123,456,789"

es6中新增了正向后顾(?<=表达式)和反(负)向后顾(?<!表达式),正向后顾(?<=表达式)表示前面要有什么,反向后顾(?<!表达式)表示前面不能有什么。

var str = 'abc1 def2'
str.match(/(?<=abc)\d+/) // 1
str.match(/(?<!abc)\d+/) // 2

命名捕获分组
我们可以通过在分组中前面加上(?<name>)给分组命名,match exec函数返回的groups中保存命名捕获分组的结果

var reg = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
var date = '2019-08-12'
let result = date.match(reg) //["2019-08-12", "2019", "08", "12", index: 0, input: "2019-08-12", groups: {year: "2019",month: "08",day: "12"}]
console.log(result.groups)  // {year: "2019",month: "08",day: "12"}

引用捕获结果
被正则表达式匹配(捕获)到的字符串会被暂存起来。其中,由分组捕获的串会从1开始编号

var reg = /(\d{4})-(\d{2})-(\d{2})/
var date = '2019-08-12'
reg.exec(date)
console.log(RegExp.$1) //2019
console.log(RegExp.$2) //08
console.log(RegExp.$3) //12

$1,$2...$9是RegExp对象的静态属性 。如果表达式模式中有括起来的子匹配,$1...$9表示第1个到第9个子匹配所捕获到的内容,如果有超过9个以上的子匹配,$1…$9属性分别对应最后的9个子匹配。

反向引用
可以引用前面捕获的分组,还需注意的是,如果引用了越界或者不存在的编号的话,就被被解析为普通的表达式

//判断是否是对称的字符
var str = 'abcba'
var reg = /(\w)(\w)(\w)\3?\2\1/
console.log(reg.test(str)) // true

反向引用命名分组\k<name>

var str = 'abcba'
var reg = /(?<first>\w)(?<two>\w)(?<three>\w?)\k<three>?\k<two>\k<first>/
console.log(reg.test(str)) // true

嵌套捕获分组
嵌套分组就是括号里面嵌套着括号,个人理解嵌套捕获分组就是从左向右捕获的基础的再加上先捕获大括号,再捕获小括号

var reg = /((\d{4})-(\d{2}))-(\d{2})/
var date = '2019-08-12'
reg.exec(date)
console.log(RegExp.$1) //2019-08
console.log(RegExp.$2) //2019
console.log(RegExp.$3) //08
console.log(RegExp.$4) //12

与replace配合
String.prototype.replace方法的传参中可以直接引用被捕获的串,我们可以利用分组结合replace很方便的做一些替换

var reg = /(\d{4})-(\d{2})-(\d{2})/
var date = '2019-08-12'
// $1...$9就是对分组的引用
date.replace(reg,'$1.$2.$3')  //2019.08.12

还可以结合命名分组

var reg = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
var date = '2019-08-12'
date.replace(reg,'$<month>/$<day>/$<year>')  //12/08/2019

结合方法

var reg = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
var date = '2019-08-12'
date.replace(reg,(...args)=>{
  console.log(args) //["2019-08-12", "2019", "08", "12", 0, "2019-08-12", {year: "2019", month: "08", day: "12"}]
  let { year, month, day } = args.slice(-1)[0]
  return month + '/' + day + '/' + year
})  // 08/12/2019

如果觉得可以,帮忙点个赞。如有不对还忘指出,谢谢。
传送门git笔记

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

推荐阅读更多精彩内容

  • 正则表达式功能: 测试字符串的某个模式。例如对一个输入字符串进行测试,看在该字符串是否存在一个电话号码模式或一个信...
    DecadeHeart阅读 595评论 0 1
  • 0、前言   作为一名前端开发者,在做表单验证或者写一些gulp任务或webpack配置时都不可避免的会用到正则,...
    风之化身呀阅读 479评论 0 0
  • 创建正则表达式 1.使用RegExp()构造函数来创建 RegExp()构造函数非常有用,特别是在需要动态创建正则...
    振礼硕晨阅读 665评论 0 0
  • 正则表达式的元字符是包含特殊含义的字符,它们有一些特殊的功能,可以控制匹配模式的方式,反斜杠后的元字符失去其特殊含...
    Miss____Du阅读 1,580评论 0 6
  • 第一部分 基础知识 一、正则申明方式 1、构造函数方式 ● 通过 new 构造一个正则表达式对象,其中第一个参数 ...
    _双眸阅读 26,784评论 2 15