概念
如何构建一个正则表达式
- 构造函数:
new RegExp("正则主体",[修饰符]) - 字面量:
/正则主体/修饰符
const reg1 = new RegExp('.com$')
const reg2 = /^aaa/
reg2 instanceof RegExp // true
模式中使用的所有元字符都建议在之前加\转义,正则表达式中的元字符包括:
( [ { \ ^ $ | ) ? * + . ] }
修饰符
-
- i(ignore case) 不区分大小写
const pattern = /hello/i
const str = 'Hello world'
console.log(pattern.ignoreCase) //true
console.log(pattern.test(str)) //true
-
- g(global) 全局
RegExp.lastIndex 如果匹配模式带有g,这个属性存储在整个字符串中下一次检索的开始位置,这个属性会被exec(),test()方法调用到(不带g永远返回0)。
- g(global) 全局
var pattern = /hello/ig;
var str = 'Hello helloworld';
console.log(pattern.global); //true
console.log(pattern.test(str)); // true
console.log(pattern.lastIndex); // 5
-
- m(multiline) 多行
如果目标字符串中不含有换行符\n,即只有一行,那么/m修饰符没有任何意义。
如果正则表达式中不含有^或$匹配字符串的开头或结尾,那么/m修饰符没有任何意义。
- m(multiline) 多行
-
- u (unicode)
加了u修饰符,会正确处理大于\uFFFF的unicode
- u (unicode)
/^\uD83D/.test('\uD83D\uDC2A') // true
/^\uD83D/u.test('\uD83D\uDC2A') // false
-
- s 默认情况下,.可以匹配任意字符,除了换行符,且.不能匹配Unicode字符,需要使用u选项启用Unicode模式才行。
ES2018引入了dotAll模式,通过s选项可以启用,这样,.就可以匹配换行符了。
/foo.bar/.test('foo\nbar'); // false
/foo.bar/s.test('foo\nbar'); // true
类
类使用[ ]来表达,用于查找某个范围内的字符
\s: 等价于[\t\n\x0B\f\r]空格\S: 等价于[^\t\n\x0B\f\r]非空格\d: 等价于[0-9]数字\D[^0-9]非数字\w: 等价于[a-zA-Z_0-9]单词字符 ( 字母、数字、下划线)\W: 等价于[^a-zA-Z_0-9]非单词字符.: 等价于[^\r\n]任意字符,除了回车与换行外所有字符\f: 等价于\x0c\cL匹配一个换页符\n: 等价于\x0a\cJ匹配一个换行符\r: 等价于\x0d\cM匹配一个回车符\t: 等价于\x09\cI匹配一个制表符\v: 等价于\x0b\cK匹配一个垂直制表符\xxx: 查找以八进制数 xxx 规定的字符\xdd: 查找以十六进制数 dd 规定的字符\uxxxx: 查找以十六进制数 xxxx 规定的 Unicode 字符
量词
量词表示匹配多少个目标对象,精确匹配长度使用`{ }
n*:{0,}匹配零个或多个nn+:{1,}匹配至少一个 n 的字符串n?:{0,1}匹配零个或一个n{n}: 匹配n次{n,m}匹配n到m次{n,}至少匹配n次`
分组
分组使用( ),作用是提取相匹配的字符串,使量词作用于分组 比如hehe{3}是把e匹配了3次而不是单词,如果希望作用于单词,可以使用分组(hehe){3}
或
分组中使用 | 可以达到或的效果 比如:T(oo|ii)m可以匹配 Toom 和 Tiim
`abToomhaTiimmm`.replace(/T(oo|ii)m/g, '-') // ab-ha-mm
反向引用
使用( )后可以使用$1-$9等来匹配
'2022-02-11'.replace(/(\d{4})\-(\d{2})\-(\d{2})/g, '$2/$3/$1') // 02/11/2022
后向引用
\n 表示后向引用,\1是指在正则表达式中,从左往右数第1个( )中的内容;以此类推,\2表示第2个( ),\0表示整个表达式。
//匹配日期格式,表达式中的\1代表重复(\-|\/|.)
const rgx = /\d{4}(\-|\/|.)\d{1,2}\1\d{1,2}/
rgx.test("2016-03-26") // true
rgx.test("2016-03.26") // false
后向引用和反向引用的区别是:\n只能用在表达式中,而$n只能用在表达式之外的地方。
分组命名 (ES9)
ES2018 之前的分组是通过数字命名的:
const pattern = /(\d{4})-(\d{2})-(\d{2})/u
const result = pattern.exec('2018-10-25')
console.log(result[0]) // 2018-10-25
console.log(result[1]) // 2018
console.log(result[2]) // 10
console.log(result[3]) // 25
现在可以通过指定分组的名称,增加代码可读性,便于维护:
const pattern = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u
const result = pattern.exec('2018-10-25')
console.log(result.groups.year) // 2018
console.log(result.groups.month) // 10
console.log(result.groups.day) // 25
分组命名还可以和String.prototype.replace方法结合:
const reDate = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/
const d = '2018-10-25'
const USADate = d.replace(reDate, '$<month>-$<day>-$<year>')
console.log(USADate) // 10-25-2018
忽略分组
如果不希望捕获某些分组,在分组内加上?:即可 比如(?:tom).(ok)那么这里$1指的就是ok
前瞻
前瞻 Lookahead 是RegExp匹配到规则的时候,向后检查是否符合断言
- 正向前瞻
(?= )后面要有xx - 负向前瞻
(?! )后面不能有xx
'1a2bc*456v8'.replace(/\w(?=\d)/g, '-') // 1-2bc*--6-8 匹配后面是数字的单词字符
'1a2bc*456v8'.replace(/\w(?!\d)/g, '-') // -a---*45-v- 匹配后面不是数字的单词字符
const pattern1 = /\d+(?= dollars)/u // 正向前瞻,匹配字符串中紧跟着是dollars的数字
const result1 = pattern1.exec('42 dollars')
console.log(result1[0]) // 42
const pattern2 = /\d+(?! dollars)/u // 负向前瞻,匹配字符串中紧跟着的不是dollars的数字
const result2 = pattern2.exec('42 pesos')
console.log(result2[0]) // 42
后顾 (ES9)
后顾 Lookbehind 是RegExp匹配到规则的时候,向前检查是否符合断言
- 正向后顾
(?<= )前面要有xx - 负向后顾
(?<! )前面不能有xx
const pattern1 = /(?<=\$)\d+/u; // 正向后顾,匹配字符串中前面是\$的数字
const result1 = pattern1.exec('$42')
console.log(result1[0]) // 42
const pattern2 = /(?<!\$)\d+/u // 负向后顾,匹配字符串中前面不是是\$的数字
const result2 = pattern2.exec('€42')
console.log(result2[0]) // 42
贪婪模式 与 非贪婪模式
正则表达式在匹配的时候默认会尽可能多的匹配,叫贪婪模式。通过在限定符后加?可以进行非贪婪匹配 比如\d{3,6}默认会匹配6个数字而不是3个,在量词{ }后加一个?就可以修改成非贪婪模式,匹配3次
`12345678`.replace(/\d{3,6}/, '-') // -78
`12345678`.replace(/\d{3,6}?/, '-') // -45678
'abbbb'.replace(/ab+?/, '-') // -bbb
优先级
优先级从高到低:
- 转义 \
- 括号( )、(?: )、(?= )、[ ]
- 字符和位置
- 或 |
属性和方法
实例属性
global:是否全文搜索,默认false,对应修饰符的g,只读ignoreCase:是否大小写敏感,默认false,对应修饰符i,只读multiline:是否多行搜索,默认false,对应修饰符m,只读flags:返回修饰符,只读lastIndex:当前表达式匹配内容的最后一个字符的下一个位置source:正则表达式的文本字符串
实例方法
test()
测试字符串参数中是否存在匹配正则表达式的字符串,使用.test的时候如果修饰符有g ,那么会正则会记住lastIndex并在下一次执行的时候从lastIndex处开始检测,如果只是为了测试是否符合正则,可以不用g或者每次都重新实例化正则表达式
const reg=/\w/g
reg.test('a') // true
reg.test('a') // false
exec()
使用正则表达式对字符串执行搜索,并将更新全局RegExp对象的属性以反映匹配结果
如果匹配失败,exec() 方法返回 null
如果匹配成功,exec() 方法返回一个数组,并更新正则表达式对象的属性
- 数组索引0:匹配的全部字符串
- 数组索引1,2..n:括号中的分组捕获
- index:属性是匹配文本的第一个字符的位置
- input:存放被检索的字符串
const str="123456@qq.com"
const ret1 = /(@)(qq.com)$/.exec(str) // ['@qq.com', '@', 'qq.com', index: 6, input: '123456@qq.com', groups: undefined]
const ret2 = /163.com$/.exec(str) // null