正则表达式
概念:
正则表达式是用于匹配字符串中字符组合的模式。在 JavaScript 中,正则表达式也是对象。这些模式被用于 RegExp 的 exec 和 test 方法, 以及 String 的 match、matchAll、replace、search 和 split 方法。
创建正则表达式
两种方法:字面量方式,构造函数方式
//字面量方式,其由包含在斜杠之间的模式组成
var re = /ab+c/;
//构造函数方式,调用RegExp对象的构造函数
var re = new RegExp("ab+c");
字符分类
正则表达式指的是斜杠/之间的部分,由字符组成,不过里面的字符有的是字面上的意思,有的却有特殊作用。
/regular expression /gim;
img 为修饰符,用于附加一些规则。ES6 中还增加了 uys 修饰符。
我们把表示字面意思的字符称为字面量字符,有特殊作用的字符称为元字符。
主要的元字符有:. ^ $ | \ ? * + ( ) [ ] { }
点字符(.)
点字符(.)表示任意字符,包含了回车(\r),换行(\n),行分隔符(\u2028),段分隔符(\u2029),以及码点大于0xFFFF的字符。
注:ES6 推出的u修饰符,能匹配上码点大于0xFFFF的字符
var reg = /\d/;
var str = "11123bcd";
var res = str.replace(reg, "a"); //将数字换为a
console.log(res); //a1123bcd 只要匹配到符合规则的就返回
位置字符(^ $)
位置字符^表示字符串的开始位置,而$表示字符串的结束位置
// 字符串中有以 abc 开头的部分
/^abc/.test("abcdef"); // true
// 字符串中有以 def 结尾的部分
/def$/.test("abcdef"); // true
// 字符串从开头到结尾只有 abc
/^abc$/.test("abc"); // true
选择符(|)
选择符( | )在正则表达式中表示"或",比如 /cat|dog/表示匹配 cat 或 dog
// 字符串中有 cat 或 dog
/cat|dog/.test("cat"); // true
/cat|dog/.test("dog"); // true
转义字符(\)
如果要在正则表达式中表示元字符,就得进行转义,即跟在\后面。
注意,如果正则表达式是以构造函数生成的,由于第一个参数是字符串,所以本身会转义,得用两个转义符号\\才行
var r = new RegExp("a\\.c"); // /a\.c/
集合类([])、脱字符(^)、连字符(-)
集合类([])用于表示一系列字符可用来匹配,相当于一个字符集合,将字符都放到[和]之间。
//字符串中有a,b,c其中一个字符
/[abc]/.test("a"); //true
/[abc]/.test("b"); //true
/[abc]/.test("c"); //true
集合类中,^不是位置字符,而是脱节字符,表示集合类之中的字符都不能用来匹配
集合类中,-也算特殊字符,称为连字符,表示连续的字符集合
//字符串中有a到z小写字母其中一个字符
/[a-z]/.test("b"); //true
/[^a-z]/.test("b"); //false
//字符串中有数字、小写字母、大写字母其中一个字符
/[0-9a-zA-Z]/.test(1); //true
注意: 连字符 -支队单个字符生效,所以[1-31]代表从1到3的字符,而不是从1到31。另外也可以对 unicode 字符生效
//字符串理由1、2、3其中之一
/[1-31]/.test(4); //flase
//字符串中有从\u0128 到\uFFFF 其中一个
/[\u018-\uFFFF]/.test("\0130\u0131\u01332"); //true
重复类({})、量词符(? * +)、贪婪模式
重复类({})用于表示也给字符的重复次数(即出现次数)
{n}:字符重复n次。{n,}:字符重复至少n次{n,m}:字符重复n到m次
//字符o重复两次
/lo{2}/.test("look"); //true
/lo{2}/.test("lok"); //flase
正则表达式中还可以用量词符来表示字符的出现的次数
?:字符出现0次或1次,相当于{0,1}*:字符出现至少 0 次,相当于{0,}+:字符出现至少1次,相当于{1,}
//字符t出现0次 或 1次
/t?est/.test("test"); //true
/t?est/.test("est"); //true
通常情况下,指定了字符的出现次数后,都是按最多的情况去匹配,这一规则称为贪婪模式.
//贪婪模式下:字符a出现1到4次,则按最多的情况返回
/a{1,4}/.exec("aaaabc")[0]; //"aaaa"
为了匹配更少的,可以采用非贪婪模式,通过在后面跟上?就可以
//非贪婪模式:字符a出现1到4次,则按最少的情况返回
/a{1,4}?/.exec("aaaabc")[0]; //"a"
不可打印字符
正则表达式对一些不可带引的特殊字符,提供了表达方式:
\cx:表示Ctrl- [X],其中X是A-Z之中任一个英文字母,用来匹配空值字符[\b]:匹配退格键(U+0008),不要与\b混淆\r:匹配回车键\n:匹配换行键\t:匹配制表符 tab(U+0009)\v:匹配垂直制表符(U+0008)\f:匹配换页符(U+000C)\0:匹配 null 字符(U+0000)\xhh:匹配一个以两位十六进制书(\x00-\xFF)表示的字符\xhhh:匹配一个以四位十六进制数(\u0000-uFFFF)表示的Unicode字符
预定义字符
预定义字符是对正则表达式中一些常用字符匹配的简写
\d:匹配0到9的任意数字,相当于[0-9]\D:匹配0到9以外的字符,相当于[^0-9]\w:匹配任意的字母,数字和下划线,相当于[a-zA-Z0-9_]\W:匹配字母,数字和下划线以外的字符,相当于[^a-zA-Z9-9_]\s:匹配空格(包括换行符,制表符,空格符等),相当于[\r\n\t\v\f]\S:匹配非空格的字符,相当于[^\r\n\t\v\f]\b:匹配词边界,表示词独立\B:匹配非词边界,表示词不独立
// 单词 world 独立
/\bworld/.test("hello world"); // true
/\bworld/.test("world hello"); // true
/\bworld/.test("hello-world"); // true
/\bworld/.test("world-hello"); // true
/world\b/.test("world hello"); // true
/world\b/.test("hello world"); // true
/world\b/.test("hello-world"); // true
/world\b/.test("world-hello"); // true
// 单词 world 不独立
/\Bworld/.test("hello world"); // false
/\Bworld/.test("helloworld"); // true
/world\B/.test("hello world"); // false
/world\B/.test("helloworld"); // true
修饰符(i g m u y s)
修饰符放在正则表达式斜杠/后面,用于附加一些规则
i:忽略大小写(ignore)g:全局匹配(global),只要剩余位置上有匹配就行,使用字符串的match方法时返回每次匹配的内容形成的数组,而不会返回分组的内容m:允许多行(multiline),只影响位置符号^和$u:Unicode模式,用来正确匹配码点大于\uFFFF的字符y:粘结(sticky),确保多值匹配时,从剩余的第一个位置能匹配上s:单行(singleline),又称dotAll模式,点字符(.)代表了所有字符,包括换行符\n等
// i 忽略大小写
/abc/.test("ABC"); // false
/abc/i.test("ABC"); // true
// g 全局匹配
"abbcbb".match(/bb/); // ["bb", index: 1, input: "abbcbb", groups: undefined]
"abbcbb".match(/bb/g); // ["bb","bb"]
// m 允许多行
/world$/.test("hello world\n"); // false
/world$/m.test("hello world\n"); // true
// u Unicode 模式
"🐪" === "\uD83D\uDC2A"; // true
/^\uD83D/u.test("\uD83D\uDC2A"); // false
/^\uD83D/.test("\uD83D\uDC2A"); // true
// y 粘连(sticky),确保多值匹配时,从剩余的第一个位置能匹配上
var str = "aaa_aa_a";
var reg1 = /a+/g;
reg1.exec(str); // ["aaa"]
reg1.exec(str); // ["aa"]
var reg2 = /a+/y;
reg2.exec(str); // ["aaa"]
reg2.exec(str); // null
// s 单行(singleline),又称 dotAll 模式,点字符(.)代表了所有的字符
/a.c/.test("a\nc"); // false
/a.c/s.test("a\nc"); // true
分组匹配
正则表达式里可以用小括号()将多个字符分为一组,以组为单位进行匹配,而不是单个字符进行匹配
//字符p重复至少一次
/group+/.test("groupp") / //true
//字符组group重复至少一次
group +
/.test('groupgroup')/ / true;
捕获
正则表达式里使用分组后,通过字符串的match方法在非全局匹配的情况下,会捕获每个分组所匹配的内容:
// 非全局匹配时,match 返回数组,第一个元素是整体匹配内容,后续的元素是分组匹配的内容
"abc".match(/(.)b(.)/); // ["abc","a","c"]
// 全局匹配时,会把匹配到的字符串返回,而不会返回分组匹配的内容
"abc".match(/(.)b(.)/g); // ["abc"]
如果想要一个分组不被match方法捕获,则可以使用(?:)的分组形势,称为非捕获组.如下:
//采用非捕获组,则不会捕获对应分组的匹配内容
"abc".match(/(?:.)b(.)/); // ["abc","c"]
正则表达式里还可以用\n ( n>=1且为正数) 的形式来引用分组,表示分组匹配的内容一致:
// 字符 b 前面的字符一样,后面的字符也一样
/(.)b(.)\1b\2/.test("abcabc") // true
// 小括号还可以嵌套,\1 和外层括号匹配内容一致,\2 和内层括号匹配内容一致
/y((..)\2)\1/.test('yabababab') // true
断言
断言指的是直接指定一个字符前面或后面会是什么,或者不是什么,主要分为 4 种:
x(?=y):先行断言(x后面是y才匹配)
// b 后面是 c 才匹配
/ab(?=c)/.test('abc') // true
/ab(?=c)/.test('ab') // false
/ab(?=c)/.test('abd') // false
x(?!y):先行否定断言(x后面不是y才匹配)
// b 后面不是 c 才匹配
/ab(?!c)/.test('abc') // false
/ab(?!c)/.test('ab') // true
/ab(?!c)/.test('abd') // true
(?<=y)x:后行断言(x前面是y才匹配)
// b 前面是 a 才匹配
/(?<=a)bc/.test('abc') // true
/(?<=a)bc/.test('bc') // false
/(?<=a)bc/.test('dbc') // false
(?<!y)x:后行否定断言(x前面不是y才匹配)
// b 前面不是 a 才匹配
/(?<!a)bc/.test('abc') // false
/(?<!a)bc/.test('bc') // true
/(?<!a)bc/.test('dbc') // true
注意,先行(lookahead)需要判断后面是不是,后行(lookbehind)需要判断前面是不是。而为什么叫法感觉不对,因为参照物是分组,我要匹配的内容在分组前面,那么就是先行,反之是后行。
具名
ES6 中提出了将分组进行命名,方便读取匹配结果,即 具名分组匹配。
形式为在分组内最前面加上 ?<组名>
/(?<数字>\d+)/.exec("ab12c3");
// ["12", "12", index:2, input: "ab12c3", groups:{"数字":"12"}, length:2]
可以看到匹配结果中,groups 对象会将具名分组的名称作为键,匹配结果作为值,如果没有具名分组,则 groups 为 undefined。
有了具名分组后,使用字符串的 replace 方法进行替换时,可以用 $<组名> 来表示分组所匹配的内容:
let re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u;
"2015-01-02".replace(re, "$<day>/$<month>/$<year>"); // "02/01/2015"
而当我们想在正则表达式中,引用下具名分组,则可以用 \k<组名> 来引用分组,当然 \n (n >= 1 且为整数)的形式也支持:
/^(?<word>[a-z]+)!\k<word>$/.test('abc!abc') // true
/^(?<word>[a-z]+)!\1$/.test('abc!abc') // true
正则表达式的常用方法
1.test(字符串):测试字符是否满足正则表达式规则,如果测试到有,则返回 true;没有则返回 falas
语法:正则表达式.test(字符串) 正则表达式提供的方法
var reg = /[123]/;
var str = "1";
var result = reg.test(str);
console.log(result); //flase
2.search(正则表达式):执行正则表达式和 String 对象之间的一个搜索匹配
语法:字符串.search(正则表达式)字符串提供的方法
var reg = /\d/; //匹配阿拉伯数字
var str = "abcdefg3sgbh";
var res = str.search(reg);
console.log(res); //7
//验证方法 找到返回下标 找不到返回-1
//在字符串中找到满足正则表达式的那一部分
3.正则表达式.exec(字符串)
exec()方法在一个指定字符串中执行一个搜索匹配,返回一个结果数组或 null.正则表达式提供的方法
var reg = /\d/;
var str = "abcd456efg";
var res = reg.exec(str);
console.log(res); //返回一个数组,内容是4
//字符串中满足正则表达式的部分提取出来
//遇到满足条件的就返回,所以只返回4
4.字符串.mathch(正则表达式)
match()方法检索返回一个字符串匹配正则表达式的结果。字符串提供的方法
var reg = /\d/;
var str = "abcd456efg";
var res = str.match(reg); //字符串中满足表达式的部分提取出来
console.log(res);
5.字符串.replace(正则表达式,新的内容)
replace()方法返回一个有替换值(replacement)替换部分或所有模式(pattern)匹配项后的新字符串。模式可以是一个字符串或者是一个正则表达式,替换值可以是一个字符串或者一个每次匹配都要调用的回调函数。如果 pattern 是字符串,则仅替换第一个匹配项。字符串提供的方法
var reg = /\d/;
var str = "11123bcd";
var res = str.replace(reg, "a"); //将数字换为a
console.log(res); //a1123bcd 只要匹配到符合规则的就返回

浙公网安备 33010602011771号