正则表达式是国际标准,跨越语言;
正则表达式是一个规则,用于验证字符串;
使用场景
数据验证
:可以测试输入字符串,以查看字符串内是否出现电话号码模式或信用卡号码模式;
替换文本
:可以使用正则表达式来识别文档中的特定文本,完全删除该文本或者用其他文本替换它;
从字符串中提取子字符串
:可以查找文档内或输入域内特定的文本;
元字符、修饰符
量词元字符
字符 | 描述 |
---|---|
* | 0 到多次,* 是贪婪的,会尽可能多的匹配文字,在它后面加上一个 ? 就可以实现非贪婪或最小匹配 |
+ | 1 到多次,+ 是贪婪的,会尽可能多的匹配文字,在它后面加上一个 ? 就可以实现非贪婪或最小匹配 |
? | 0 或 1 次 |
{ n } | 出现 n 次 (n 为 0 或正整数) |
{ n, } | 出现 n 到多次 (n 为 0 或正整数) |
{ n, m } | 出现 n-m 次 (n 为 0 或正整数) |
字符类
字符 | 描述 |
---|---|
[ ] | 匹配括号内的任意一个字符 /[abc]/g 匹配所有的字符 “a”、“b”、“c”, /[0-9]/g 匹配所有 0-9 中的数字 |
[^ ] | 匹配除了括号内的字符以外的任意一个字符 /[^abc]/g 匹配除了字符 “a”、“b”、“c” 以外的所有任意字符 |
匹配特定类型的字符
字符 | 描述 |
---|---|
\d | 匹配一个数字字符,等价于 /[0-9]/ |
\D | 匹配一个非数字字符,等价于 /[^0-9]/ |
\w | 匹配字母、数字、下划线,等价于 /[A-Za-z0-9_]/ |
\W | 匹配非字母、数字、下划线,等价于 /[^A-Za-z0-9_]/ |
特殊字符
字符 | 描述 |
---|---|
\ | 转义字符,用于匹配特殊字符本身 |
. | 匹配除换行符 (\n、\r) 之外的任何单个字符,相等于 /[^\n\r]/ |
| | 用于指定多个模式的选择 |
非打印字符
字符 | 描述 |
---|---|
\n | 匹配一个换行符 |
\r | 匹配一个回车符 |
\s | 匹配任何空白字符,包括空格、制表符、换页符等等 |
\S | 匹配任何非空白字符 |
\t | 匹配一个制表符 |
边界匹配
字符 | 描述 |
---|---|
^ | 匹配字符串的开头 (精确匹配) |
$ | 匹配字符串的结尾 (精确匹配) |
\b | 匹配单词边界,它匹配一个 单词的开始 或 单词的结束 的位置,而不匹配任何实际的字符 \bword\b 匹配整个单词 “word”,但不匹配 “words” 或 “sword” |
\B | 匹配非单词边界,即匹配 单词的内部、非单词的开头或结尾 \Bword\B 匹配 “swords” 中的 “word”,但不匹配 “word”、“sword”、 “words” |
分组和捕获
概念说明
- 零宽:只匹配位置,零宽意味着断言在匹配时不会"消耗"字符串,它只是对位置进行条件判断,不包括匹配位置之前或之后的字符在匹配结果中;
- 先行:表示断言发生在匹配位置之前;
- 后行:表示断言发生在匹配位置之后;
- 正向:匹配括号中的表达式,即断言所作的条件判断是肯定的,即只有当条件成立时,匹配才成功;
- 负向:不匹配括号中的表达式,即断言所作的条件判断是否定的,即只有当条件不成立时,匹配才成功;
字符 | 描述 |
---|---|
( ) | 用于分组和捕获子表达式,它会把匹配到的内容保存到内存中,开发者可以使用 $n 来代表第 n 个 ( ) 中匹配到的内容 |
(?:pattern) | 用于分组但不捕获子表达式,它匹配的内容不会被保存,所以无法使用 $n 获取 |
(?=pattern) | 零宽正向先行断言,exp1(?=exp2) 匹配后面是 exp2 的 exp1,匹配结果中不包含 exp2 |
(?!pattern) | 零宽负向先行断言,exp1(?!exp2) 匹配后面不是 exp2 的 exp1,匹配结果中不包含 exp2 |
(?<=pattern) | 零宽正向后行断言,(?<=exp2)exp1 匹配前面是 exp2 的 exp1,匹配结果中不包含 exp2 |
(?<!pattern) | 零宽负向后行断言,(?<!exp2)exp1 匹配前面不是 exp2 的 exp1,匹配结果中不包含 exp2 |
修饰符
字符 | 描述 |
---|---|
i | 不区分大小写,将匹配设置为不区分大小写,搜索时不区分大小写 |
m | 多行匹配,使边界字符 ^ 和 $ 匹配每一行的开头和结尾,而不是整个字符串的开头和结尾 |
g | 全局匹配,查找所有的匹配项 |
剖析
元字符
-
^ :以哪一个元字符作为开始
// 必须以数字开始 let reg = /^\d/; reg.test('2020baidu'); // true reg.test('baidu2020'); // false
-
$ :以哪一个元字符作为结束
// 必须以数字结束 let reg = /\d$/; reg.test('2020baidu'); // false reg.test('baidu2020'); // true // ^ $都不加:字符串中包含符合规则的内容就可以 let reg = /\d/; // ^ $都加:字符串只能是和规则一致的内容 let reg = /^\d$/;
-
\ :转义字符(普通->特殊->普通)
// .不是小数点,是除了\n外的任意字符 let reg = /^2.3$/; reg.test("2.3"); //=>true reg.test("2@3"); //=>true reg.test("23"); //=>true // 基于转义字符,让其只能代表小数点 reg = /^2\.3$/; reg.test("2.3"); //=>true reg.test("2@3"); //=>false reg.test("23"); //=>false // \把特殊符号转换为普通的符号,\d原本代表 0-9 的数字,现在是字符串 \d reg = /^\\d$/; reg.test('\d'); //=>false reg.test('\\d'); //=>true,
-
x | y :x 或者 y 中的一个字符
let reg = /^18|29$/; // 18 开始或者 29 结尾的 reg.test('18'); //=>true reg.test('129'); //=>true reg.test('189'); //=>true reg.test('1829'); //=>true reg.test('829'); //=>true reg.test('182'); //=>true reg.test('19'); //=>false // 直接 x|y 会存在很多优先级问题,一般都使用 () 进行分组,()会改变处理的优先级 reg = /^(18|29)$/;// 18 或者 29 reg.test("18"); // true reg.test("29"); // true reg.test("129"); // false reg.test("189"); // false reg.test("1829"); // false reg.test("829"); // false reg.test("182"); // false
-
[]:
JavaScriptJavaScript// [xyz]:x 或者 y 或者 z 中的一个字符 let reg = /^[@+]$/; reg.test("@"); //=>true reg.test("+"); //=>true reg.test("++"); //=>false
// [] 中不存在多位数 let reg = /^[18]$/; reg.test("1"); //=>true reg.test("8"); //=>true reg.test("18"); //=>false //=> 1 或 3-6之间的数 或 9 reg = /^[13-69]$/; reg.test("1"); //=>true reg.test("9"); //=>true reg.test("4"); //=>true reg.test("0"); //=>false reg.test("2"); //=>false
反向引用
-
反向引用:捕获组捕获到的内容在正则表达式内部进行引用,则为反向引用;
-
利用 \捕获组编号 反向引用之前的 捕获组;
// 找出该字符串中连续的字符 var s = "aaaabbbbdefgg"; var reg = /(\w)\1+/g; while (result = reg.exec(s)) { console.log(result); } // [ 'aaaa', 'a', index: 0, input: 'aaaabbbbdefgg', groups: undefined ] // [ 'bbbb', 'b', index: 4, input: 'aaaabbbbdefgg', groups: undefined ] // [ 'gg', 'g', index: 11, input: 'aaaabbbbdefgg', groups: undefined ]
捕获组
-
普通捕获组
// 得到每个日期的 年、月、日 var s = "2015-5-1, 2019-6-19"; var reg = /(\d{4})-(\d{1,2})-(\d{1,2})/g; while ((result = reg.exec(s))) { console.log(result); } // [ '2015-5-1', '2015', '5', '1', index: 0, input: '2015-5-1, 2019-6-19', groups: undefined ] // [ '2019-6-19', '2019', '6', '19', index: 10, input: '2015-5-1, 2019-6-19', groups: undefined ]
-
具名捕获组
(?<命名>pattern)
:捕获组可以命名,最后都放入结果的 groups 中// 得到每个日期的 年、月、日 var s = "2015-5-1, 2019-6-19"; var reg = /(?<year>\d{4})-(?<month>\d{1,2})-(?<day>\d{1,2})/g; while (result = reg.exec(s)) { console.log(result); } // [ '2015-5-1', '2015', '5', '1', index: 0, input: '2015-5-1, 2019-6-19', groups: { year: '2015', month: '5', day: '1' } ] // [ '2019-6-19', '2019', '6', '19', index: 10, input: '2015-5-1, 2019-6-19', groups: { year: '2019', month: '6', day: '19' } ]
正向预查、负向预查
-
零宽正向先行断言,exp1(?=exp2) 匹配后面是 exp2 的 exp1,匹配结果中不包含 exp2
var s = "ricepudding.cn"; var reg = /ricepudding(?=\.cn)/g; while ((result = reg.exec(s))) { console.log(result); } // [ 'ricepudding', index: 0, input: 'ricepudding.cn', groups: undefined ]
-
零宽负向先行断言,exp1(?!exp2) 匹配后面不是 exp2 的 exp1,匹配结果中不包含 exp2
var s = "ricepudding.1cn"; var reg = /ricepudding(?!\.cn)/g; while ((result = reg.exec(s))) { console.log(result); } // [ 'ricepudding', index: 0, input: 'ricepudding.1cn', groups: undefined ]
-
零宽正向后行断言,(?<=exp2)exp1 匹配前面是 exp2 的 exp1,匹配结果中不包含 exp2
var s = "ricepudding.cn"; var reg = /(?<=ricepudding)\.cn/g; while ((result = reg.exec(s))) { console.log(result); } // [ '.cn', index: 11, input: 'ricepudding.cn', groups: undefined ]
-
零宽负向后行断言,(?<!exp2)exp1 匹配前面不是 exp2 的 exp1,匹配结果中不包含 exp2
var s = "ricepudding1.cn"; var reg = /(?<!ricepudding)\.cn/g; while ((result = reg.exec(s))) { console.log(result); } // [ '.cn', index: 12, input: 'ricepudding1.cn', groups: undefined ]
在线工具
169.多数元素
上一篇