本文是 重温基础 系列文章的第九篇。今日感受:时间管理 - 角色管理法。
系列目录:
【复习资料】ES6/ES7/ES8/ES9 资料整理(个人整理)
【重温基础】1. 语法和数据类型
【重温基础】2. 流程控制和错误处理
【重温基础】3. 循环和迭代
【重温基础】4. 函数
【重温基础】5. 表达式和运算符
【重温基础】6. 数字
【重温基础】7. 时间对象
【重温基础】8. 字符串
本章节复习的是 JS 中的正则表达式,JS 中用来匹配字符串的强大工具。
前置知识:JS 中的正则表达式是用来匹配字符串中指定字符组合的模式。另外需要记住:正则表达式也是对象。
1. 创建正则表达式
使用一个正则表达式字面量:
let reg = /ab+c/;
let reg = /^[a-zA-z]/gi;
使用 RegExp 对象:
new RegExp(str[, attr])接收 2 个参数,str 是一个字符串,指定正则表达式匹配规则,attr 可选,表示匹配模式,值有 g(全局匹配),i(区分大小写的匹配)和 m(多行匹配)。
let reg = new RegExp(‘ab+c’);
let reg = new RegExp(/^[a-zA-z]/, “gi”);
let reg = new RegExp(“^[a-zA-z]”, “gi”);
正则表达式的返回值,是一个新的 RegExp 对象,具有指定的模式和标志。返回信息介绍:
对象
属性
描述
案例中对应的值
reg
lastIndex
下一个匹配的索引(仅在使用 g 参数时可用)
0
reg
source
模式文本。在正则表达式创建时更新,不执行。
“ab+c”
reg
ignoreCase
是否使用了 “i” 标记使正则匹配忽略大小写。
true
reg
global
是否使用了 “g” 标记来进行全局的匹配。
true
reg
multiline
是否使用了 “m” 标记使正则工作在多行模式。
false
关于正则表达式的一些方法属性,文章后面介绍,这里先复习定义和使用。
2. 使用正则表达式
JS 的正则表达式可以被用于:
RegExp 对象的 exec 和 test 方法;
String 对象的 match、replace、search 和 split 方法。
2.1 RegExp 对象方法
方法
介绍
exec
检索字符串中指定的值。返回找到的值,并确定其位置。
test
检索字符串中指定的值。返回 true 或 false。
2.1.1 exec(str)
str: 需要检索的字符串。若检索成功,返回匹配的数组,否则返回 null。
let str = “hello leo!”;
let reg = new RegExp(“leo”, “g”);
let result = reg.exec(str);
// 也可以写成
let result = /leo/g.exec(“hello leo!”);
/*
[
0: “leo”,
groups: undefined,
index: 6,
input: “hello leo!”,
length: 1
]
*/
let result2 = /(leo \S)/g.exec(“hello leo hi leo!”);
/*
0: “leo hi”
1: “leo hi”
2: “hi”
groups: undefined
index: 6
input: “hello leo hi leo!”
length: 3
*/
返回信息介绍:
对象
属性
描述
案例中对应的值
result
[0]
匹配到的所有字符串
“leo”
result
input
初始字符串。
“hello leo!”
result
index
在输入的字符串中匹配到的以 0 开始的索引值。
6
result2
[1],…,[n]
括号中的分组捕获
[1]=> “leo hi”;[2] => “hi”
2.1.2 test(str)
str: 需要检索的字符串。若匹配成功返回 true 否则 false。等价于 reg.exec(str) != null。
let str = “hello leo!”;
let res = /^leo/.test(str); // fasle
let res1 = /^leo/.test(str); // true
^str 表示匹配以 str 开头的字符串,这些符号文章后面会介绍。
2.2 String 对象方法
方法
介绍
search
检索与正则表达式相匹配的值。
match
找到一个或多个正则表达式的匹配。
replace
替换与正则表达式匹配的子串。
split
把字符串分割为字符串数组。
2.2.1 search
str.search(reg):str: 被检索的源字符串。reg: 可以是需要检索的字符串,也可以是需要检索的 RegExp 对象,可以添加标志,如 i。
若检索成功,返回第一个与 RegExp 对象匹配的字符串的起始位置,否则返回 -1。
let str = “hello leo!”;
let res = str.search(/leo/g); // 6
let str1 = “hello leoleoleoleo!”;
let res1 = str.search(/leo/g); // 6
let res2 = str.search(/pingan/g); // -1
2.2.2 match
str.match(reg):str: 被检索的源字符串。reg: 可以是需要检索的字符串,也可以是需要检索的 RegExp 对象,可以添加标志,如 i。
若检索成功,返回与 reg 匹配的所有结果的一个数组,数组的第一项是进行匹配完整的字符串,之后的项是用圆括号捕获的结果,否则返回 null。
let str = ‘For more information, see Chapter 3.4.5.1’;
let reg = /see (chapter \d+(\.\d)*)/i;
let result = str.match(reg);
/*
logs [‘see Chapter 3.4.5.1’,
‘Chapter 3.4.5.1’,
‘.1’,
index: 22,
input: ‘For more information, see Chapter 3.4.5.1’ ]
*/
‘see Chapter 3.4.5.1’ 是整个匹配。‘Chapter 3.4.5.1’ 被 '(chapter \d+(\.\d)*)’ 捕获。‘.1’ 是被'(\.\d)’ 捕获的最后一个值。‘index’ 属性(22) 是整个匹配从零开始的索引。‘input’ 属性是被解析的原始字符串。
2.2.3 replace
将字符串中指定字符替换成其他字符,或替换成一个与正则表达式匹配的字符串。str.replace(sub/reg,val):
str: 源字符串
sub: 使用字符串来检索被替换的文本
reg: 使用 RegExp 对象来检索来检索被替换的文本
val: 指定替换文本
返回替换成功之后的字符串,不改变源字符串内容。
let str = “hello leo!”;
let res = str.replace(‘leo’,’pingan’);//”hello pingan!”
val 可以使用特殊变量名:
变量名
代表的值
$$
插入一个 “$”。
$&
插入匹配的子串。
$
插入当前匹配的子串左边的内容。
$’
插入当前匹配的子串右边的内容。
$n
假如第一个参数是 RegExp 对象,并且 n 是个小于 100 的非负整数,那么插入第 n 个括号匹配的字符串。提示:索引是从 1 开始
let str = “hello leo!”;
let res = str.replace(/(\w+)\s* \s*(\w+)/, “$2:$1”);
// “leo:hello!”
2.2.4 split
将一个字符串,按照指定符号分割成一个字符串数组。str.split(sub[, maxlength]):
str: 源字符串
sub: 指定的分割符号或正则
maxlength: 源字符串
let str = “hello leo!”;
let res = str.split(); //[“hello leo!”]
let res = str.split(“”); //[“h”, “e”, “l”, “l”, “o”, ” “, “l”, “e”, “o”, “!”]
let res = str.split(” “);//[“hello”, “leo!”]
let res = str.split(/\s+/);//[“hello”, “leo!”]
let res = str.split(“”,3);//[“h”, “e”, “l”]
2.3 使用情况
当我们想要查找一个字符串中的一个匹配是否找到,可以用 test 或 search 方法。
当我们想要得到匹配的更多信息,我们就需要用到 exec 或 match 方法。
3. 正则表达式符号介绍
详细的每个符号的用法,可以查阅 W3school JavaScript RegExp 对象
3.1 修饰符
修饰符
描述
i
执行对大小写不敏感的匹配。
g
执行全局匹配(查找所有匹配而非在找到第一个匹配后停止)。
m
执行多行匹配。
let str = “hello leo!”
let res = /Leo/i.test(str); // i 不区分大小写 所以返回 true
let res = /Leo/.test(str); // fasle
3.2 方括号
用于查找指定返回之内的字符:
表达式
描述
[abc]
查找方括号之间的任何字符。
[^abc]
查找任何不在方括号之间的字符。
[0-9]
查找任何从 0 至 9 的数字。
[a-z]
查找任何从小写 a 到小写 z 的字符。
[A-Z]
查找任何从大写 A 到大写 Z 的字符。
[A-z]
查找任何从大写 A 到小写 z 的字符。
[adgk]
查找给定集合内的任何字符。
[^adgk]
查找给定集合外的任何字符。
(red)
查找任何指定的选项。
let str = “hello leo!”;
let res = str.match(/[a-m]/g);
//[“h”, “e”, “l”, “l”, “l”, “e”]
let res = str.match(/[^a-m]/g);
//[“o”, ” “, “o”, “!”]
3.3 元字符
元字符是拥有特殊含义的字符:
元字符
描述
.
查找单个字符,除了换行和行结束符。
\w
查找单词字符。
\W
查找非单词字符。
\d
查找数字。
\D
查找非数字字符。
\s
查找空白字符。
\S
查找非空白字符。
\b
匹配单词边界。
\B
匹配非单词边界。
\0
查找 NUL 字符。
\n
查找换行符。
\f
查找换页符。
\r
查找回车符。
\t
查找制表符。
\v
查找垂直制表符。
\xxx
查找以八进制数 xxx 规定的字符。
\xdd
查找以十六进制数 dd 规定的字符。
\uxxxx
查找以十六进制数 xxxx 规定的 Unicode 字符。
let str = “hello leo hi pingan!”;
let res = str.match(/o\s/g);
//[“o “, “o “]
let res = str.match(/\s/g);
//[” “, ” “, ” “]
3.4 量词
量词
描述
n+
匹配任何包含至少一个 n 的字符串。
n*
匹配任何包含零个或多个 n 的字符串。
n?
匹配任何包含零个或一个 n 的字符串。
n{X}
匹配包含 X 个 n 的序列的字符串。
n{X,Y}
匹配包含 X 至 Y 个 n 的序列的字符串。
n{X,}
匹配包含至少 X 个 n 的序列的字符串。
n$
匹配任何结尾为 n 的字符串。
^n
匹配任何开头为 n 的字符串。
?=n
匹配任何其后紧接指定字符串 n 的字符串。
?!n
匹配任何其后没有紧接指定字符串 n 的字符串。
let str = “hello leo!”;
let res = str.match(/^hello/g);
// [“hello”]
let res = str.match(/^pingan/g);
//null
4. 正则表达式拓展(ES6)
4.1 介绍
在 ES5 中有两种情况。
参数是字符串,则第二个参数为正则表达式的修饰符。
let a = new RegExp(‘abc’, ‘i’);
// 等价于
let a = /abx/i;
参数是正则表达式,返回一个原表达式的拷贝,且不能有第二个参数,否则报错。
let a = new RegExp(/abc/i);
// 等价于
let a = /abx/i;
let a = new RegExp(/abc/, ‘i’);
// Uncaught TypeError
ES6 中使用:第一个参数是正则对象,第二个是指定修饰符,如果第一个参数已经有修饰符,则会被第二个参数覆盖。
new RegExp(/abc/ig, ‘i’);
4.2 字符串的正则方法
常用的四种方法:match()、replace()、search()和 split()。
4.3 u 修饰符
添加 u 修饰符,是为了处理大于 uFFFF 的 Unicode 字符,即正确处理四个字节的 UTF-16 编码。
/^\uD83D/u.test(‘\uD83D\uDC2A’); // false
/^\uD83D/.test(‘\uD83D\uDC2A’); // true
由于 ES5 之前不支持四个字节 UTF-16 编码,会识别为两个字符,导致第二行输出 true,加入 u 修饰符后 ES6 就会识别为一个字符,所以输出 false。
注意:加上 u 修饰符后,会改变下面正则表达式的行为:
(1)点字符
点字符 (.) 在正则中表示除了换行符以外的任意单个字符。对于码点大于 0xFFFF 的 Unicode 字符,点字符不能识别,必须加上 u 修饰符。
var a = “????”;
/^.$/.test(a); // false
/^.$/u.test(a); // true
(2)Unicode 字符表示法
使用 ES6 新增的大括号表示 Unicode 字符时,必须在表达式添加 u 修饰符,才能识别大括号。
/\u{61}/.test(‘a’); // false
/\u{61}/u.test(‘a’); // true
/\u{20BB7}/u.test(‘????’); // true
(3)量词
使用 u 修饰符后,所有量词都会正确识别码点大于 0xFFFF 的 Unicode 字符。
/a{2}/.test(‘aa’); // true
/a{2}/u.test(‘aa’); // true
/????{2}/.test(‘????????’); // false
/????{2}/u.test(‘????????’); // true
(4)i 修饰符
不加 u 修饰符,就无法识别非规范的 K 字符。
/[a-z]/i.test(‘\u212A’) // false
/[a-z]/iu.test(‘\u212A’) // true
检查是否设置 u 修饰符:使用 unicode 属性。
const a = /hello/;
const b = /hello/u;
a.unicode // false
b.unicode // true
4.4 y 修饰符
y 修饰符与 g 修饰符类似,也是全局匹配,后一次匹配都是从上一次匹配成功的下一个位置开始。区别在于,g 修饰符只要剩余位置中存在匹配即可,而 y 修饰符是必须从剩余第一个开始。
var s = ‘aaa_aa_a’;
var r1 = /a+/g;
var r2 = /a+/y;
r1.exec(s) // [“aaa”]
r2.exec(s) // [“aaa”]
r1.exec(s) // [“aa”] 剩余 ‘_aa_a’
r2.exec(s) // null
lastIndex 属性: 指定匹配的开始位置:
const a = /a/y;
a.lastIndex = 2; // 从 2 号位置开始匹配
a.exec(‘wahaha’); // null
a.lastIndex = 3; // 从 3 号位置开始匹配
let c = a.exec(‘wahaha’);
c.index; // 3
a.lastIndex; // 4
返回多个匹配:一个 y 修饰符对 match 方法只能返回第一个匹配,与 g 修饰符搭配能返回所有匹配。
‘a1a2a3’.match(/a\d/y); // [“a1”]
‘a1a2a3’.match(/a\d/gy); // [“a1”, “a2”, “a3”]
检查是否使用 y 修饰符:使用 sticky 属性检查。
const a = /hello\d/y;
a.sticky; // true
4.5 flags 属性
flags 属性返回所有正则表达式的修饰符。
/abc/ig.flags; // ‘gi’
5. 正则表达式拓展(ES9)
在正则表达式中,点 (.) 可以表示任意单个字符,除了两个:用 u 修饰符解决四个字节的 UTF-16 字符,另一个是行终止符。终止符即表示一行的结束,如下四个字符属于“行终止符”:
U+000A 换行符(n)
U+000D 回车符(r)
U+2028 行分隔符(line separator)
U+2029 段分隔符(paragraph separator)
/foo.bar/.test(‘foo\nbar’)
// false
上面代码中,因为. 不匹配 \n,所以正则表达式返回 false。换个醒,可以匹配任意单个字符:
/foo[^]bar/.test(‘foo\nbar’)
// true
ES9 引入 s 修饰符,使得. 可以匹配任意单个字符:
/foo.bar/s.test(‘foo\nbar’) // true
这被称为 dotAll 模式,即点(dot)代表一切字符。所以,正则表达式还引入了一个 dotAll 属性,返回一个布尔值,表示该正则表达式是否处在 dotAll 模式。
const re = /foo.bar/s;
// 另一种写法
// const re = new RegExp(‘foo.bar’, ‘s’);
re.test(‘foo\nbar’) // true
re.dotAll // true
re.flags // ‘s’
/ s 修饰符和多行修饰符 / m 不冲突,两者一起使用的情况下,. 匹配所有字符,而 ^ 和 $ 匹配每一行的行首和行尾。
参考资料
1.MDN 正则表达式 2.W3school JavaScript RegExp 对象
本部分内容到这结束
Author
王平安
E-mail
pingan8787@qq.com
博 客
www.pingan8787.com
微 信
pingan8787
每日文章推荐
https://github.com/pingan8787…
ES 小册
es.pingan8787.com