正则表达式

正则表达式.png

公司的小伙伴希望能讲一下正则表达式,于是趁着这个机会自己也把正则表达式的重新学习了一下,由于不同语言对正则表达式提供了不同的方法支持,以下所有的正则测试均基于Javascript

1. 元字符

正则表达式中的字符可以认为有两类,一类被称为元字符,代表的是有在正则表达式中有特殊含义的字符,另一类就是普通字符。
个人认为元字符分为了三类:固有语义,简写字符集和分组匹配

1.1 固有语义的字符

1.1.1 选择字符

选择字符有两种[][^][]表示匹配结果包含[]中的任意字符,[^]则表示匹配结果不能包含[^]中的字符

/[1234]/.test('1'); // true
/[1234]/.test('5'); // false
/[^1234]/.test('2'); // false
/[^1234]/.test('5'); // true

需要注意的是[][^]中的字符,除开部分特殊字符外(例如:[,],-等),都是自带转义属性。也就是说[]中的字符都不再具有特殊意义

// 在正则中‘.’是任意匹配的意思,但是[]中失去了其本来的意义
/./.test(1); // true
/[.]/.test(1);  // false
/[.]/.test('.');  // true

1.1.2 重复字符

表示一个字符出现次数包括:?, *, +, {m, n}

// 0次或1次匹配
/[a]?/.test('a'); // true
/[a]?/.test('b'); // true
// 0次或多次匹配
/[a]*/.test('a'); // true
/[a]*/.test('b'); // true
// 1次或多次匹配
/[a]+/.test('a'); // true
/[a]+/.test('b'); // false
// 出现m到n次
/[a]{2,3}/.test('aab'); // true
/[a]{2,3}/.test('abab'); // false

1.1.3 锚点字符

有表示开始的^和表示结束的$,用于限制正则匹配的开始和结束

/[1]/.test('12'); // true
// 以1开头
/^[1]/.test('21'); // false
/^[1]/.test('12'); // true
// 以1结尾
/[1]$/.test('12'); // false
/[1]$/.test('21'); // true

1.1.4 转义字符

使用\来进行将一些元字符进行转义,从而使得元字符可以进行匹配

/[]/.test('[]'); // false
/\[\]/.test('[]'); // true

1.1.5 通配字符

使用.来匹配任意字符,只要匹配字符串不为空匹配结果都为真

/./.test('a-1sd'); // true    

1.1.6 或字符

使用|来对多个字符取并集匹配

/1|2/.test('1'); // true, 等价于/[12]/.test('1')
/1|2/.test('2'); // true, 等价于/[12]/.test('1')
/The|to/.test('to'); // true

1.1.7 非贪婪匹配

在重复字符后面使用?来进行非贪婪匹配,非贪婪匹配是指在匹配字符对时候尽可能少的匹配

// 使用replace函数来验证
'aaab'.replace(/[a]+/g, '='); // =b
'aaab'.replace(/[a]+?/g, '='); // ===b

上面的例子中:
第一个使用了贪婪模式,因此\[a]+\将匹配aaa,因此执行替换的时候将aaa替换为了=
第二个使用了非贪婪匹配,因此\[a]+?\将分别匹配每个a,因此最后将每个a分别替换为=aaa就变为===

1.2 简写字符集

将一些字符,和转义符号配合使用,可以得到一些正则表达式默认匹配范围

1.2.1 字符数字匹配集

使用\w可以匹配字符数字,相当于[a-zA-Z0-9_],而\W匹配所有非字符数字,相当于[^a-zA-Z0-9_]

/\w/.test('1'); // true
/\W/.test('1'); // false

1.2.2 数字匹配集

使用\d匹配数字,相当于[0-9],同样\D匹配非数字,相当于[^0-9]

/\d/.test('1'); // true
/\D/.test('1'); // false

1.2.3 空格匹配集

使用\s匹配空格,相当于[ ],使用\S匹配非空格,相当于[^ ]

/\s/.test(' '); // true
/\S/.test(' '); // false

1.2.4 其他

其他还包括换行符匹配\n,回车匹配\r,制表符匹配\t

1.3 分组

正则表达式中可以将匹配进行分组,并可以分别获取匹配的分组,同时表达式中也可以指定分组的引用

1.3.1 分组匹配

使用()可以将正则表达式进行分组

/(The)|(To)/.test('The'); // true

看上去和之前的差不多,但是,这里可以在正则表达式中,利用捕获模式(/ + 数字)和替换模式($ + 数字)获取,获得对应分组的引用,分组的计数是从1开始的

// 捕获模式
/(The)(To)\1/.test('TheTo'); // false
/(The)(To)\1/.test('TheToThe'); // true
/(The|To)\1/.test('TheThe'); // true
/(The|To)\1/.test('ToTo'); // true
/(The|To)\1/.test('TheTo'); // false
// 替换模式
'TheTo'.replace(/(The)(To)/, '$2$1') // ToThe

1.3.2 非获取匹配

在分组匹配中,可以使用(?)的方式,来进行匹配,但是匹配后不进行存储使用,也就是不能使用捕获模式和替换模式的方式获取到分组信息

1.3.2.1 匹配不获取

使用(?:)去匹配字符,通常和|来组合使用

/Test(?:er|or)/.test('Tester'); // true
/Test(?:er|or)/.test('Testor'); // true
/Test(er|or)\1/.test('Testerer'); // true
/Test(er|or)\1/.test('Testoror'); // true
/Test(?:er|or)\1/.test('Testeror'); // false
/Test(?:er|or)\1/.test('Tester\1'); // true

1.3.2.2 正向预查匹配

使用(?=)来进行正向匹配,匹配字符串开始处进行查找

/Windows(?=2000|3000)/.test('Windows3000'); // true
/Windows(?=2000|3000)/.test('Windows4000'); // false

1.3.2.3 正向预查不匹配

使用(?!)来进行匹配和(?=)刚好相反

/Windows(?!2000|3000)/.test('Windows3000'); // false
/Windows(?!2000|3000)/.test('Windows4000'); // true

1.3.2.4 反向预查匹配

使用(?<=)来进行匹配

/(?<=2000|3000)Windows/.test('3000Windows'); // true
/(?<=2000|3000)Windows/.test('4000Windows'); // false

1.3.2.4 反向预查不匹配

使用(?<!)来进行匹配,和(?<=)相反

/(?<!2000|3000)Windows/.test('3000Windows'); // false
/(?<!2000|3000)Windows/.test('4000Windows'); // true

2. 匹配模式

常用的匹配模式有三个:i, g, m,不同的语言支持的匹配模式的会有所不同

2.1 忽略大小匹配

使用i做为匹配模式,可以忽略匹配中的大小写

/[A]/.test('a'); // false
/[A]/i.test('a'); // true

2.2 全局匹配

使用g做为匹配模式,可以匹配字符串中的所有字符,而不是第一个字符

'abcabcabc'.replace(/[a]/, '='); // =bcabcabc
'abcabcabc'.replace(/[a]/g, '='); // =bc=bc=bc

2.2 多行匹配

使用m做为匹配模式,可以匹配多行字符,通常和g一起使用

3. Javascript支持正则的方法

3.1 支持的方法

各语言都提供了各种支持正则都方法,Javascript以下方法都支持正则表达式的使用:

RegExp.prototype.exec()
RegExp.prototype.test()
String.prototype.replace()

3.2 lastIndex

Javascript中,在正则表达式对象存在lastIndex属性,每进行一次匹配,这个属性会进行更新为当前匹配位置,并以在下一次匹配时,以这个位置开始进行匹配

let str = 'abc';
let reg = /[a]/g;
reg.test(str); // true
console.log(reg.lastIndex); // 1
reg.test(str); // false
// 由于匹配失败,所以会被重置为0
console.log(reg.lastIndex); // 0

4. 总结

正则表达式的识别主要是区别元符号和普通符号的,同时注意转义符号的使用特点,读懂正则表达式就不难了。

5. 参考

你应该学习正则表达式
Learn-regex-easy-way
百度百科-正则表达式
MDN-RegExp

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

推荐阅读更多精彩内容