原文 前端之巅 公众号的精选文章,感谢作者分享。 正则表达式真的很6,可惜你不会写
1、元字符
| 元字符 | 基本说明 |
|---|---|
| . | 匹配除换行符以外的任意字符 |
| \w | 匹配非特殊符号,即匹配字母/数字/下划线/汉字 |
| \s | 匹配任意的空白符 |
| \d | 匹配数字 |
| ^ | 匹配字符串的开始 |
| $ | 匹配字符串的结束 |
2、重复限定符
| 语法 | 基本说明 |
|---|---|
| * | 重复0次或多次 |
| + | 重复1次或多次 |
| ? | 重复0次或1次 |
| {n} | 重复n次 |
| {n,} | 重复n次或以上 |
| {n,m} | 重复n次到m次 |
3、分组
| 语法 | 基本用法 |
|---|---|
| () | ^(ab)* |
4、转义
| 语法 | 基本用法 |
|---|---|
| \ | ^(\(ab\))* --->转义() |
5、条件或
| 语法 | 基本用法 |
|---|---|
| | | ('你'|'我') |
6、区间
| 语法 | 基本用法 |
|---|---|
| [] | [0-4] |
7、零宽断言
1)正向先行断言(正前瞻)
语法:(?=pattern)
作用:匹配 pattern 表达式的前面内容,不返回本身。-->前
'<span class="read-count">阅读数:641</span>'.match(/\d+(?=\<\/span\>)/)
// ["641"]
2)正向后行断言(正后顾)
语法:(?<=pattern)
作用:匹配 pattern 表达式的后面的内容,不返回本身。后<--
'<span class="read-count">阅读数:641</span>'.match(/(?<=\<span class="read-count"\>阅读数:)\d+/)
// ["641"]
3)负向先行断言(负前瞻)
语法:(?!pattern)
作用:匹配非 pattern 表达式的前面内容,不返回本身。 -->前 左到右
有正向也有负向,负向在这里其实就是非的意思。 举个栗子:比如有一句 “我爱祖国,我是祖国的花朵” 现在要找到不是'的花朵'前面的祖国
'我是祖国的花朵,我爱我的祖国'.match(/祖国(?!的花朵)/)
//["祖国"]
4)负向后行断言(负后顾)
语法:(?<!pattern)
作用:匹配非 pattern 表达式的后面内容,不返回本身。 后<--
(?<=)和(?<!) —JavaScript不支持
8、 捕获和非捕获
单纯说到捕获,他的意思是匹配表达式,但捕获通常和分组联系在一起,也就是“捕获组”。
捕获组:匹配子表达式的内容,把匹配结果保存到内存中中数字编号或显示命名的组里,以深度优先进行编号,之后可以通过序号或名称来使用这些匹配结果。
根据命名分为数字编号捕获组和命名编号捕获组
1)数字编号捕获组
第0组是整一个表达式,第一组开始为分组
var number = '020-85653333'
var arr= /(0\d{2})-(\d{8})/.exec(number)
console.log(arr)
//["020-85653333", "020", "85653333", index: 0, input: "020-85653333", groups: undefined]
//另一种获取值,test()、exec()、以及String的正则方式执行完都可以
console.log(RegExp.$1) //'020' 第一个分组的值
console.log(RegExp.$2) //'world' 第二个分组的值
//这里的$1、$2与方法二里的RegExp.$1、RegExp.$2作用是相同的。
var n_number = number.replace( /(0\d{2})-(\d{8})/,"$2 $1");
console.log(n_number) //"85653333 020"
2)命名编号捕获组
语法(?<name>exp),取个别名
var number = '020-85653333'
var arr= /(?<quhao>0\d{2})-(?<haoma>\d{8})/.exec(number)
console.log(arr)
//["020-85653333", "020", "85653333", index: 0, input: "020-85653333", groups: {quhao: "020", haoma: "85653333"}]
//这里可以通过groups获取值
3)非捕获组
语法:(?:exp),简单来说就是不进行保存的捕获组
var number = '020-85653333'
var arr= /(?:0\d{2})-(\d{8})/.exec(number)
console.log(arr)
//["020-85653333", "85653333", index: 0, input: "020-85653333", groups: undefined]
//这里 020就没有保存
9、反向引用
捕获会返回一个捕获组,这个分组是保存在内存中,不仅可以在正则表达式外部通过程序进行引用,也可以在正则表达式内部进行引用,这种引用方式就是反向引用。
根据捕获组的命名规则,反向引用可分为:
- 数字编号组反向引用:\k 或\number
- 命名编号组反向引用:\k 或者'name'
捕获组通常是和反向引用一起使用的,捕获组是匹配子表达式的内容按序号或者命名保存起来以便使用。
//查找一串字母"aabbbbgbddesddfiid"里成对的字母
var str = 'aabbbbgbddesddfiid';
console.log(str.match(/(\w)\1/g));
// ["aa", "bb", "bb", "dd", "dd", "ii"]
// 把字符串 abcbbabcbcgbddesddfiid 中 abc 换成 a
var str = 'abcbbabcbcgbddesddfiid'
console.log(str.replace(/(a)bc/g,'$1'))
//abbabcgbddesddfiid
10、贪婪和非贪婪
贪婪
当正则表达式中包含能接受重复的限定符时,通常的行为是(在使整个表达式能得到匹配的前提下)匹配尽可能多的字符,这匹配方式叫做贪婪匹配。
特性:一次性读入整个字符串进行匹配,每当不匹配就舍弃最右边一个字符,继续匹配,依次匹配和舍弃(这种匹配 - 舍弃的方式也叫做回溯),直到匹配成功或者把整个字符串舍弃完为止,因此它是一种最大化的数据返回,能多不会少。
前面的【重复限定符】就是贪婪量词:
const str = '61762828 176 2991 44 871';
console.log(str.match(/\d{3,6}/g)); // ["617628", "176", "2991", "871"]
const str = '61762828 176 2991 87321';
console.log(str.match(/(\d{1,2})(\d{3,4})/g)); // ["617628", "2991", "87321"]
非贪婪匹配
当正则表达式中包含能接受重复的限定符时,通常的行为是(在使整个表达式能得到匹配的前提下)匹配尽可能少的字符,这匹配方式叫做懒惰匹配。
特性:从左到右,从字符串的最左边开始匹配,每次试图不读入字符匹配,匹配成功,则完成匹配,否则读入一个字符再匹配,依此循环(读入字符、匹配)直到匹配成功或者把字符串的字符匹配完为止。
懒惰量词是在贪婪量词后面加个“?”
- *? 重复任意次,但尽可能少重复
- +? 重复1次或更多次,但尽可能少重复
- ?? 重复0次或1次,但尽可能少重复
- {n,m}? 重复n到m次,但尽可能少重复
- {n,}? 重复n次以上,但尽可能少重复
/(\d{1,2}?)(\d{3,4})/
11、 反义
元字符的都是要匹配什么什么,当然如果你想反着来,不想匹配某些字符,正则也提供了一些常用的反义元字符:
| 元字符 | 解释 |
|---|---|
| \W | 匹配任意不是字母,数字,下划线,汉字的字符 |
| \S | 匹配任意不是空白符的字符 |
| \D | 匹配任意非数字的字符 |
| \B | 匹配不是单词开头或结束的位置 |
| [^x] | 匹配除了x以外的任意字符 |
| [^aeiou] | 匹配除了aeiou这几个字母以外的任意字符 |