# 3、RegExp 对象
# 一、 概述
正则表达式(regular expression)是一种表达文本模式,通过给定模式匹配文本。JS 的正则是参考了 Perl5 建立的
新建正则表达式的方式有两种,
(1)字面量,以斜杠表示开始和结束。
var reg = /xyz/;
(2)RegExp 构造函数。
var reg = new RegExp("xyz");
第一种方式直观便利,而且第一种是在引擎编译代码时新建,第二种是在代码运行时新建。所以实际应用中,基本采用字面量定义正则表达式。
RegExp
构造函数还可以接受第二个参数,表示修饰符。
var regExp = new RegExp("xyz", i);
// 等价于
var regExp = /xyz/i;
# 二、实例属性
# 2.1 RegExp.prototype.ignoreCase
查看是否设置了i
修饰符
# 2.2 RegExp.prototype.global
查看是否设置了g
修饰符
# 2.3 RegExp.prototype.multiline
查看是否设置了m
修饰符
# 2.4 RegExp.prototype.flags
列出所有修饰符
# 2.5 RegExp.prototype.lastIndex
返回一个整数,表示下一次开始搜索的位置。该属性可读写
# 2.6 RegExp.prototype.source
返回正则表达式的字符串形式(不包括反斜杠),该属性只读。
例子:
var reg = /abc/gim;
reg.ignoreCase; // true
reg.global; // true
reg.multiline; // true
reg.flags; // "gim"
reg.lastIndex; // 0
reg.source; // "abc"
# 三、实例方法
# 3.1 RegExp.prototype.test()
查看实例对象的 test()方法返回一个布尔值,表示当前模式是否能匹配字符串。
/cat/.test("cats and dogs"); // true
- 带有
g
修饰符时,可以通过lastIndex
属性开始搜索位置,正则表达式内部会记住上一次的 lastIndex 的属性
var str = "_x234_x_5555_xx"; // 找出所有x位置的索引 --- 1、6、13、14
var reg = /x/g;
reg.lastIndex; // 0 从0开始
reg.test(str); // true
reg.lastIndex; // 2 从2开始检索
reg.test(str); // true
reg.lastIndex; // 7 从7开始检索
reg.test(str); // true
reg.lastIndex; // 14 从14开始检索
reg.test(str); // true
reg.lastIndex; // 15 从15开始检索
reg.test(str); // false
reg.lastIndex; // 0 从0开始检索
所以索引就是lastIndex - 1;
- 案例:结合上面的方法和 substr 实现替换文本中特定文字的功能,文字颜色自定义 --- 代码位置/code/RegExp/reg1.html
# 3.2 RegExp.prototype.exec()
- 遇到匹配的返回一个数组,否则返回 null
var s = "_x_x";
var reg1 = /x/;
var reg2 = /y/;
reg1.exec(s); // ["x"]
reg2.exec(s); // null
- 如果正则有圆括号代表组匹配,会返回匹配多次后的数组
var r1 = /_(x)/;
r1.exec("_x"); // ["_x", "x", index: 0, input: "_x_x", groups: undefined]
先整体匹配一次得到“_x”,在括号中的匹配一次得到"x"。index 是最开始匹配到的索引,input 是原字符串
var r = /a(b+)a/;
var arr = r.exec("_abbba_aba_");
arr; // ["abbba", "bbb"]
arr.index; // 1
arr.input; // "_abbba_aba_"
利用g
修饰符允许多次匹配的特点,可以用一个循环完成全部匹配。
var reg = /a/g;
var str = "abc_abc_abc";
while (true) {
var match = reg.exec(str);
if (!match) break;
console.log("#" + match.index + ":" + match[0]);
}
// #0:a
// #4:a
// #8:a
案例:重写替换文字
var str = "你怎么这么美呢,你美的不可方物,让我不忍打断";
var reg = /美/g;
var result = "";
function test(str1) {
const res = reg.exec(str1);
if (!res) {
return;
} else {
const txtArr = [...res.input];
txtArr[res.index] = "丑";
result = yy.join("");
test(result);
}
return result;
}
const aa = test(str); // "你怎么这么丑呢,你丑的不可方物,让我不忍打断"
比较 test()方法和 exec() 的不同:(1)返回结果不同:test 返回布尔;exec 返回数组。 (2)匹配结束返回的判断条件不同:test 返回 false,lastIndex 为 0;exec 返回的是 null,
相同点是:一次只能返回一次的结果可以配合”g“修饰符循环遍历出所有匹配值及索引。可以设置
lastIndex
属性设置从第几位开始匹配
# 四、字符串的实例方法
# 4.1 String.prototype.match()
字符串实例的 match 方法进行正则匹配,返回所有(需要配合 g)匹配到结果的数组,成员是所有的子字符串。lastIndex
属性设置无效从是从弟一个字符开始
var s = "_x_x";
var r1 = /x/;
var r2 = /y/;
s.match(r1); // ['x']
s.match(r2); // null
var reg = /x/g;
s.match(reg); // ["x","x"]
var r = /a|b/g;
r.lastIndex = 7;
"xaxb".match(r); // ['a', 'b']
r.lastIndex; // 0
# 4.2 String.prototype.search()
字符串对象search
方法,返回第一个满足条件的陪陪结果在整个字符串中的位置。没有匹配返回-1
var str = "qwert"
str.search(/w/) //1
=> str.search("w") // 1
str.search(/o/) // -1
# 4.3 String.prototype.replace()
字符串对象的replace
方法可以替换匹配的值。接受两个参数,第一个是正则表达式,便是搜索模式,第二个是替换的内容。
str.replace(search, replacement);
正则表达式如果不加g
那就替换第一个匹配成功的值,否则替换所有成功的值
var str = "你好美啊,美女"; // 替换成你好帅啊,帅哥
str.replace(/美/g, "帅").replace(/女/, "哥");
console.log(str); // 你好帅啊,帅哥
案例:消除字符串首尾两端的空格。
var str = " #id div.class "
法(1) => str.trimStart().trimEnd()
法(2) => str.replace(/^\s+|\s+$/g,'')
replace
方法的第二个参数可以使用美元$
,用来指代所替换的内容。
- $&: 匹配的子字符串
- $`:匹配解构前面的文本。
- $': 匹配文本后面的文本
- $n: 匹配成功后的第 n 组内容,n 是从 1 开始的自然数
- $$: 待指美元$.
// "你好,小明" 改成 "小明,你好"
"hello world".replace(/(\w+)\s(\w+)/, "$2 $1");
// "world hello"
"abc".replace("b", "[$`-$&-$']");
// "a[a-b-c]c"
- 案例:查找替换一段文字中的指定文字并高亮,替换
--- 代码位置/code/RegExp/reg3.html
# 4.3 String.prototype.split()
字符串对象split
方法按照正则规则分割字符串,返回一个由分割后的各部分组成的数组。第一个参数是正则表达式,第二个是返回数组的最大成员数
str.split(separator, [limit]);
// 非正则分割 // "你好,小明" 改成 "小明,你好"
"你好,小明".split(',').reverse().join() "小明,你好"
// 正则分割去掉多余的空格
"s sa ".trim()
'a , b, c'.split(/ , *|, */).join() // 通过结构匹配成数组在转化成文本
// 返回最大成员数
'a , b, c'.split(/ , *|, */,2) // ['a','b']
案例: split() 实现文字替换非常简单
"你好美啊,美的很".split(/美/).join("丑");
# 五、匹配规则
# 5.1 字面量字符和元字符
某个字符只表示它字面上的含义就是字面量字符比如
/美/.test("好美啊"); // true
除了字面量字符还有一部分字符有特殊含义,不代表字面的意思,我们叫他们"院子赋",主要有以下几个。
(1) 点字符( . )
点字符匹配任意的一个的字符。(除换行回车行分隔符,端分隔符)
/c.t/ // 匹配中间任何字符如"cot1_","c-t",但是多字符"coot"不可以
/c..t/.test('cddt') // true
**(2) 位置字符 **
位置字符用来提示字符所处的位置,主要有两个
^
: 表示字符串开始的位置$
:表示字符串结束的位置
// 要匹配的内容的句首必须与字面量的值
/^美/.test("美羊羊,你好美啊!") // true
// 要匹配的内容的句尾必须与字面量的值
/^美/.test("美羊羊,你好美") // true
// 句首到句尾只能出现美
/^美$/.test('美')
// 如果不加,就是匹配哪里有都可以
/美/.test('你好美!') // true
**(3) 选择符 ( | ) **
数线在正则表达式中表示‘或者(OR)’, 即cat|dog
表示匹配 cat 或者 dog
/^cat|dog/.test("cat145"); // true
# 5.2 转义符
正则中有很多特殊含义的元字符,如果要匹配他们本身,就需要在他们前面加反斜杠"/",比如匹配+
需要写成\+
/1+1/.test('1+1')
/1\+1/.test('1+134') // true
注意:如果使用 RegExp 构造函数的话,需要两个\\
因为字符串内部反斜杠也需要转译,然后正则再转译一次
const reg = new RegExp("1\\+1");
reg.test("1+1"); // true
const reg = new RegExp("1+1");
reg.test("1+1"); // false
像这样需要转译的字符一共有 12 个:^
、.
、[
、$
、(
、)
、|
、*
、+
、?
、{
和\
# 5.3 特殊字符
对一些不能打印的特殊字符,也提供了表达方式。
常用的有以下几个
\n
匹配换行键\r
匹配回车键\t
匹配 tab\f
匹配换页符\0
匹配 null 字符
# 5.4 字符类
字符类(class)[]
表示从一系列字符中选择,匹配到其中一个即可。如[xyz]表示能匹配到 x、y、z 中的任意一个即可。
/[你好美啊]/.test("我不知道你怎么这么美呢?"); // true
// 字符串中含有表达式中的任意一个字符即可
**(1) 脱字符 ( ^ ) **
^
在元字符中表示位置开头,但是用到字符类[]
中第一个位置出现表示脱字符
比如 [ ^xyz ] 意思是一定要包含 x、y、z 之外的其他字符
/[^test]/.test('tghjkl') // true
/[^test]/.test('123') // true
/[^test]/.test('test') // false
/[^]/.test('匹配任意包括换行符')
(2) 连字符 ( - )
连字符为连续序列的字符提供简写形式( - ) , 比如字符的连续范围,[abc]可以写成[a-c],
[0123456789]可以写成[0-9], 同理 A-Z 可以写成[A-Z]
/[0-9A-Xa-z]/.test('2sS') // true
/[^0-9A-Xa-z]/.test('1qZ-') // true
# 5.5 预定义模式
预定义模式是某些常见模式的简写
\d
代表 0~9 之间任意数字,相当于[0-9]\D
代表 0 ~ 9 以外的字符,相当于[ ^0-9 ]\w
代表的是任意字母、数字和下划线,相当于[A-Za-z0-9]\W
代表的是除所有任意字母、数字和下划线之外,相当于[ ^A-Za-z0-9 ]\s
匹配空格(包含换行符、制表符、空格符),相当于[ \t\r\n\v\f]\S
匹配非空格的字符,相当于[^ \t\r\n\v\f]
。\b
匹配词的边界\B
匹配非词的边界,即词的内部
// \s 的例子
/\s/.test('dfg ggg') // true
// \b 的例子 匹配的词必须独立存在于开头,能区分出来这个词 同理 \B 相反
/\bword/.test('hello world') // true
/\bert/.test('2345c.ertddddd') // true
/\Bert/.test('2345c.ertddddd') // false
一般正则表达式遇到\n
会停止匹配
var html ="Hello\n world";
/.*/.exec(html)[0] // Hello
因为点字符( . ) 不匹配换行符,导致匹配结果不符合原意。使用[\s\S]
代替一切字符
var html = "Hello\n world";
/[\s\S]*/.exec(html)[0]; //Hello\n world"
# 5.6 重复类
模式的精准匹配次数,使用大括号( {} ) 表示, { n } 表示恰好重复 n 次,{ n, }表示至少重复 n 次,{ n, m} 表示至少重复 n 次,最多重复 m 次。
/lo{2,}k/.test('look') // true
/lo{2,5}k/.test('looook') // true
# 5.7 量词类
量词符用来设定某个模式出现的次数。
?
问号表示某个模式出现 0 次或 1 次,等同于{0,1}*
星号表示某个模式出现 0 次或者多次,等同于{0,}+
加号表示某个模式出现了 1 次或者多次,等同于{1,}
// t 出现了0次或者1次用? 不出现可以
/t?est/.test('test') // true
/t?est/.test('est') // true
// t 出现了1次或多次 用+ 必须出现最少一次
/t+est/.test(est) // false
/t+est/.test(tttest) // true
// t 出现了0次或多次 用* 不出现也可以
/t*est/.test(es) // true
/t*es/.test(es) // true
# 5.8 贪婪模式
?、*、+ 三个量词符,默认都是最大可能匹配,即匹配知道下一个字符不满足匹配规则为止。这种被称为贪婪模式。
var s = "aaa";
s.match(/a+/); // ["aaa"]
s.match(/a?/); // ["a"]
s.match(/a*/); // ["aaa"]
如果匹配时想改成非贪婪模式只需要在后面加一个问号'?', 一旦条件满足,就不再往下匹配。如+? 匹配到后出现 1 次停止。*? 匹配到出现 0 次停止 ?? 匹配到 0 次
"abb".match(/ab*/); // ["abb"]
"abb".match(/ab*?/); // ["a"]
"abb".match(/ab+/); // ["abb"]
"abb".match(/ab+?/); // ["ab"]
"abb".match(/ab?/); // ["ab"] 贪婪模式下匹配到1次,非贪婪匹配到0次
"abb".match(/ab??/); // ["a"]
# 5.9 修饰符
修饰符表示模式的附加规则,放在正则模式的最尾部。
可以单个使用也可以多个一起使用
var reg = /test/i;
var reg = /test/gi;
(1)g 修饰符(global)
正则默认匹配成功就会停止向下继续匹配。g
修饰符表示全局匹配。正则对象将匹配全部符合条件的结果,主要用于搜索和替换。
var reg = /b/;
var str = "abba";
reg.test(str) // true
reg.test(str) // true
reg.test(str) // true
...
var reg = /b/g;
var str = "abba";
reg.test(str) // true r1.lastIndex = 2
reg.test(str) // true r1.lastIndex = 3
reg.test(str) // false r1.lastIndex = 0
不加 g 每次都匹配到第一个成功后停止,而加 g 之后,每次成功后,下次匹配从下一个开始匹配,直到全部匹配完。lastIndex 为 0
(2)i 修饰符(ignoreCase)
默认情况下,正则对象区分字母的大小写,加上 i 修饰符以后,忽略大小写。
/abc/.test("ABC") / // false
abc /
i.test("ABC"); // true
(3)m 修饰符(multiline)
m 修饰符表示多行模式,会修改^和$的行为。默认情况下不加m修饰符时,^和$匹配字 符串的开始和结尾处,加上 m 修饰符之后, 会匹配每一行的行首和行尾,多用于\n 换行 中。
/^ab/.test("er/nab") / // true
ab$ /
m.test("er\nab\n"); // true
# 5.10 组匹配
()
用来表示分组匹配
/ab+/.test(abb) / // true
ab +
/.test(abab) / / true;
- 用来分组捕获
"abc".match(/(.)b(.)/); // ["abc", "a", "c", index: 0, input: "abc", groups: undefined]
2020-3-01