正则表示式在线测试工具网站,并以图例的方式呈现正则表达式:regexper.com
本文章内容通过学习Samaritan89老师的网课而总结的知识点
- RegExp对象
- 元字符
- 字符类
- 范围类
- 预定义类及边界
- 量词
- 正则贪婪模式与非贪婪模式
- 分组
- 前瞻
- 正则表达式的对象属性
- 正则表达式对象方法
- 跟正则表达式非常相关的字符串对象方法
1. RegExp对象
实例化RegExp对象有一下两种方法
- 使用字面量实例化
var reg = /\bis\b/ 'He is a boy. This is a dogis.'.replace(reg,'IS') //He IS a boy. This is a dogis. var reg = /\bis\b/g 'He is a boy. This is a dogis.'.replace(reg,'IS') //He IS a boy. This IS a dogis.
- 使用构造函数实例化
//使用构造函数实例化 var reg = new RegExp('\\bis\\b','g') 'He is a boy. This is a dogis.'.replace(reg,'IS') //He IS a boy. This IS a dogis. var reg = /\bis\b/gi 'He Is a boy. This Is a dogis.'.replace(reg,'0') //He 0 a boy. This 0 a dogis.
正则的修饰符有以下几种:
符号 | 解释 | 默认值 |
---|---|---|
g | global 全文搜索 | fasle,默认搜索到第一个匹配停止 |
i | ignore case 忽略大小写 | false,默认大小写敏感 |
m | multiple lines 多行搜索 | false,默认不匹配多行 |
2. 元字符
正则表达式由两种基本字符类型组成:
- 原义wenbenzifu
- 元字符
元字符是在正则表达式中有特殊含义的非子母字符
常用的有:* + ? $ ^ . \ () {} [] ,这些在下文篇幅中一一讲述,以及以下常用字符:
字符 | 含义 |
---|---|
\t | 水平制表符 |
\v | 垂直制表符 |
\n | 换行符 |
\r | 回车符 |
\0 | 空字符 |
\f | 换页符 |
3. 字符类
类:指符合某些特性的对象,是个泛指
用 元字符[ ] 匹配某类字符
例子:
'a1b2c3d4'.replace(/[abc]/g,'X')
//X1X2X3d4
在类[]中,使用元字符^创建反向类/负向类,如下:
//表达式[^abc]表示不是字符a或b或c的内容
'a1b2c3d4'.replace(/[^abc]/g,'X')
//aXbXcXXX
4. 范围类
正则表达式提供的范围类,如
[a-z]来连接两个字符,表示从a到z的任意字符,此表达的是闭区间,包括a和z
例子:
'a1b2c3x4z9'.replace(/[a-z]/g,'P')
// P1P2P3P4P9
在[ ] 组成的类内部是可以连写的[a-zA-Z]
'Aa1Bb2c3x4z9ASDFQW'.replace(/[a-zA-Z]/g,'P')
//"PP1PP2P3P4P9PPPPPP"
匹配数字和横线,即再单加一个-
'2019-03-09'.replace(/[0-9-]/g,'P')
//PPPPPPPPPP
5. 预定义类及边界
5.1 预定义类
预定义类是为了匹配常见的的字符类
字符 | 等价类 | 含义 |
---|---|---|
. | [^\r\n] | 除了回车符、换行符之外的所有字符 |
\d | [0-9] | 数字字符 |
\D | [^0-9] | 非数字字符 |
\s | [\t\n\x0B\f\r] | 空白符 |
\S | [^\t\n\x0B\f\r] | 非空白字符 |
\w | [a-zA-Z_0-9] | 单词字符(子母、数字、下划线) |
\W | [^-zA-Z_0-9] | 非单词字符 |
例子:匹配 ab+数字+任意字符 的字符串
/ab\d./
等价于 /ab[0-9][^\r\n]/
5.2边界匹配字符####
字符 | 含义 |
---|---|
^ | 以xxx开始 |
$ | 以xxx结束 |
\b | 单词边界 |
\B | 非单词边界 |
单词边界和非单词边界例子:
'This is a boy'.replace(/is/g,'0')
//Th0 0 a boy
'This is a boy'.replace(/\bis\b/g,'0')
//This 0 a boy
'This is a boy'.replace(/\Bis\b/g,'0')
//Th0 is a boy
字符串的首尾匹配例子:
'@123@abc@'.replace(/@./g,'Q')
//Q23Qbc@
'@123@abc@'.replace(/^@./g,'Q')
// Q3@abc@
'@123@abc@'.replace(/.@/g,'Q')
// @12QabQ
'@123@abc@'.replace(/.@$/g,'Q')
//@123@abQ
多行字符串的每行首尾匹配例子
'@123\n@456\n@789'.replace(/^@\d/g,'X')
//X23\n@456\n@789
'@123\n@456\n@789'.replace(/^@\d/gm,'X')
//X23\nX56\nX89
6. 量词
例子:匹配一个连续出现5次数字的字符串
/\d\d\d\d\d/
等价于/\d{20}/
量词字符如下
字符 | 含义 |
---|---|
? | 出现零次或一次(最多一次) |
+ | 出现一次或多次(最少一次) |
* | 出现零次或多次(任意次) |
{n} | 出现n次 |
{n,m} | 出现n到m次 |
{n,} | 最少出现n次 |
例子:
'12343432'.replace(/\d?/,'z')
// "z2343432"
'12343432'.replace(/\d+/,'z')
// "z" 为什么匹配所有的数组,而不是匹配一个?看下一篇幅讲述
'12343432'.replace(/\d*/,'z')
// "z"
'12343432'.replace(/\d{4}/,'z')
// "43432"
'12343432'.replace(/\d{4,7}/,'z')
// "z2"
'12343432'.replace(/\d{4,}/,'z')
// "z"
7. 正则贪婪模式与非贪婪模式
一般情况下,正则是默认尽可能的匹配,即贪婪模式,如下例子
'12345678'.replace(/\d{3,6}/,'z')
//z78
开启非贪婪模式的方法:在量词后面添加问号
'12345678'.replace(/\d{3,6}?/,'z')
//z45678
'12345678'.replace(/\d{3,6}?/g,'z')
//zz78
8. 分组
8.1分组 ()
使用场景:匹配字符串连续出现三次的场景
例如:/Byron{3}/
只能匹配连续3次的n,单词不重复
所以可以使用 元字符() 达到分组的功能,使量词作用域分组
var reg = /(Byron){3}/
'a1b2c3d4'.replace(/[a-z]\d{3}/g,'X')
// "a1b2c3d4"
'a1b2c3d4'.replace(/([a-z]\d){3}/g,'X')
// "Xd4"
8.2 或 |
使用 元字符| 达到或的效果,而不需要分组
'ByronCasper'.replace(/Byron|Casper/g,'X')
// "XX"
也可以在分组中使用
'ByronsperByrCasper'.replace(/Byr(on|Ca)sper/g,'X')
// "XX"
8.3 反向引用
反向引用可以捕获分组内容,用$n
(n表示第n个分组)表示,同时$&
表示整个正则表达式匹配的内容.例子如下:
'2019-03-10'.replace(/(\d{4})-(\d{2})-(\d{2})/g,'$2/$3/$1')
// "03/10/2019"
'2019-03-10'.replace(/(\d{4})-(\d{2})-(\d{2})/g,'时间:$&')
//"时间:2019-03-10"
8.4 忽略分组
如不希望捕获某些分组,需在分组的前面加上?:
,例子:
'Byron1ok'.replace(/(?:Byron).(ok)/,'$1')
// "ok"
9. 前瞻
而前瞻就是在正则表达式匹配到规则的时候,向前检查是否符合断言。
对前的解释:从文本头部向尾部开始解析,文本尾部方向,称为‘前’。
后顾/后瞻方向与之方向相反,但是javascript不支持后顾
前瞻中的正则表达式称为断言,又分为肯定/正向匹配和否定/负向匹配
名称 | 正则 | 含义 |
---|---|---|
正向前瞻 | exp(?=assert) | 匹配到exp后,其后面字符是否能匹配assert的正则 |
负向前瞻 | exp(?!assert) | 匹配到exp后,其后面字符是否不能匹配assert的正则 |
例子:
'a2*34vv'.replace(/\w(?=\d)/g, 'X')
//X2*X4vv
'a2*34vv'.replace(/\w(?!\d)/g, 'X')
//aX*3XXX
10. 正则表达式的对象属性
- global:是否全文搜索,默认为false
- ignore case:是否大小写敏感,默认是fasle
- multiline:多行搜索,默认值是false
- lastIndex:是当前表达式匹配内容的最后一个字符的下一个开始搜索的位置
- source:正则表达式的文本字符串
var reg1 = /\w/;
var reg2 = /\w/gim;
reg1.global //false
reg2.multiline //true
11. 正则表达式对象方法
11.1 RegExp.prototype.test(str)
用于测试字符串参数重是否存在匹配正则表达式模式的字符串,如果存在则返回true,否则返回false
但此方法,会有以下bug
var reg1 = /\w/
var reg2 = /\w/g
reg1.test('a')//true
reg2.test('ab')//true
reg2.test('ab')//true
reg2.test('ab')//false
reg2.test('ab')//true
reg2.test('ab')//true
reg2.test('ab')//false
会有以上原因主要是因为lastIndex此属性
正则对象的test()执行后,其自身的lastIndex属性值+1,循环着
解决方法:
- 每次都实例化一个 (/\w/g).test('ab'),然而每次实例化一个对象需要内存开销的
- 使用exec方法
11.2 RegExp.prototype.exec(str)
用途:使用正则表达式模块对字符串执行搜索,并将更新全局RegExp对象的属性以反映匹配结果
如果没有匹配的文本则返回null,否则返回一个结果数组,数组有两个额外的属性
- index:生命匹配文本的第一个字符的位置
- input:存放被检索的字符串string
非全局调用(即没有修饰符g)
- 返回数组
- 第一个元素是与正则表示相匹配的文本
- 第二个元素是与RegExpObject的第一个子表达式相匹配的文本(如果有的话)
- 第三个元素是与RegExp对象的第二个子表达式相匹配的文本(如果有的话),以此类推
- 子表达式就是分组的内容
var ts = '1a2b3c4d5e'
var reg3 = /\d(\w)\d/
var ret = reg3.exec(ts)
console.log(reg3.lastIndex+' '+ret.index+' '+ret.toString())
//0 0 1a2,a
console.log(reg3.lastIndex+' '+ret.index+' '+ret.toString())
//0 0 1a2,a
对整个字符串进行搜索,能获得到具体的值:
var ts = '1a2b3c4d5e'
var reg4 = /\d(\w)\d/g, ret
while(ret = reg4.exec(ts)){
console.log(reg4.lastIndex+' '+ret.index+' '+ret.toString())
}
//2 3 0 1a2,a
//2 7 4 3c4,c
12. 跟正则表达式非常相关的字符串对象方法
12.1 String.prototype.search(reg)
用途:检索与正则表达式相匹配的子字符串
- 方法返回第一个匹配结果的index,搜索不到返回-1
- search()方法不执行全局匹配,忽略标志g,并且总是从字符串的开始进行
- search参数不是正则的都会尝试转换成正则
'a1b2c3d1'.search('1')
//1
'a1b2c3d1'.search(/1/)
//1
'a1b2c3d1'.search(1)
//1
12.2 String.prototype.match(reg)
用途:match()检索字符串,返回匹配的结果数组,没有则null
有两个对象属性
- index:声明匹配文本的起始字符在字符串的位置
- input:声明对stringObject的引用
- 若是非全局调用的话(无g),是和正则表达式方法的exec用途相反
- 若是全局调用,match只是返回数组,不会有index什么的
例子:
String.prototype.split(reg)
'a,b,c,d'.split(',')
'a1b2c3d4e'.split(/\d/g)
// ["a", "b", "c", "d", "e"]
12.3 String.prototype.replace
三个用法:
- String.prototype.replace(str, replaceStr)
- String.prototype.replace(reg, replaceStr)
- String.prototype.replace(reg, function(){})
上面的回调函数在每次匹配替换的时候调用,有四个参数
- 匹配字符串
- 正则表达式分组内容,没有分组则没有该参数
- 匹配项在字符串中的index
- 原字符串
'a1b1c1'.replace('1',2)
//a2b1c1
'a1b1c1'.replace(/1/g,2)
//a2b2c2
// 需要实现的目标:'a1b2c3d4' => 'a2b3c4d5'
'a1b2c3d4'.replace(/\d/g,function(match, index, origin){
console.log(index)
return parseInt(match)+1
})
// 1
// 3
// 5
// 7
// "a2b3c4d5"
'a1b2c3d4'.replace(/(\d)(\w)(\d)/g,function(match, group1, group2,group3, index, origin){
console.log(match)
return group1+group3
})
//1b2
//3d4
//"a12c34"