「本章节复习的是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对象方法
代码语言:javascript复制检索字符串中指定的值。返回找到的值,并确定其位置。
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
^str
表示匹配以str
开头的字符串,这些符号文章后面会介绍。
「注意:」
若正则使用全局标志( g
),则test()
会改变正则表达式的 lastIndex
属性,连续调用test()
方法,后续的执行将会从 lastIndex
处开始匹配字符串,(exec()
同样改变正则本身的 lastIndex
属性值):
var regex = /leo/g;
// regex.lastIndex is at 0
regex.test('leo'); // true
// regex.lastIndex is now at 3
regex.test('leo'); // false
2.2 String对象方法
代码语言:javascript复制检索与正则表达式相匹配的值。
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可以使用特殊变量名」:
代码语言:javascript复制插入一个 "$"。
代码语言:javascript复制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 修饰符
代码语言:javascript复制执行对大小写不敏感的匹配。
代码语言:javascript复制let str = "hello leo!"
let res = /Leo/i.test(str); // i 不区分大小写 所以返回true
let res = /Leo/.test(str); // fasle
3.2 方括号
用于查找指定返回之内的字符:
代码语言:javascript复制查找方括号之间的任何字符。
代码语言:javascript复制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 元字符
元字符是拥有特殊含义的字符:
代码语言:javascript复制查找单个字符,除了换行和行结束符。
代码语言:javascript复制let str = "hello leo hi pingan!";
let res = str.match(/os/g);
//["o ", "o "]
let res = str.match(/s/g);
//[" ", " ", " "]
3.4 量词
代码语言:javascript复制匹配任何包含至少一个 n 的字符串。
代码语言:javascript复制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中使用: 第一个参数是正则对象,第二个是指定修饰符,如果第一个参数已经有修饰符,则会被第二个参数覆盖。
代码语言:javascript复制new RegExp(/abc/ig, 'i');
4.2 字符串的正则方法
常用的四种方法:match()
、replace()
、search()
和split()
。
4.3 u修饰符
添加u
修饰符,是为了处理大于uFFFF
的Unicode字符,即正确处理四个字节的UTF-16编码。
/^uD83D/u.test('uD83DuDC2A'); // false
/^uD83D/.test('uD83DuDC2A'); // 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(/ad/y); // ["a1"]
'a1a2a3'.match(/ad/gy); // ["a1", "a2", "a3"]
「检查是否使用y
修饰符」:
使用sticky
属性检查。
const a = /hellod/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('foonbar')
// false
上面代码中,因为.
不匹配n
,所以正则表达式返回false
。
换个醒,可以匹配任意单个字符:
/foo[^]bar/.test('foonbar')
// true
ES9引入s
修饰符,使得.
可以匹配任意单个字符:
/foo.bar/s.test('foonbar') // true
这被称为dotAll
模式,即点(dot
)代表一切字符。所以,正则表达式还引入了一个dotAll
属性,返回一个布尔值,表示该正则表达式是否处在dotAll
模式。
const re = /foo.bar/s;
// 另一种写法
// const re = new RegExp('foo.bar', 's');
re.test('foonbar') // true
re.dotAll // true
re.flags // 's'
/s
修饰符和多行修饰符/m
不冲突,两者一起使用的情况下,.
匹配所有字符,而^
和$
匹配每一行的行首和行尾。
参考资料
1.MDN 正则表达式 2.W3school JavaScript RegExp 对象