转义符 \
转义字符是字符的一种间接表示方式。在特殊语境中,无法直接使用字符自身
- eg:想用单引号包裹单引号,可以使用
\'
let str = '你非常\'优秀\'';
console.log(str); // 你非常'优秀'
- 如果想显示转义符
\
,可以写\\
let str = '你非常\\优秀\\';
console.log(str); // 你非常\优秀\
- 一些规定好的转义字符:
\n
换行符、\t
水平制表符、\r
回车符…
正则
- 正则表达式是字符串的一种匹配模式,说白了就是检索字符串中特定字符的规则
创建正则
① 使用构造函数创建:
let reg = new RegExp();
-
JS 提供了一个内置构造函数
RegExp()
(regular expression),用来创建正则表达式接收 2 个参数:① 正则的规则、② 修饰符
i
m
g
let reg = new RegExp('test'); // 实例化一个正则对象
console.log(reg); // /test/
② 使用简洁语法创建:
let reg = /正则规则/修饰符;
let reg = /text/;
console.log(reg); // /test/
-
一般情况下,推荐使用简洁语法创建
但对于字符串变量,只能使用构造函数创建
let str = 'text';
let reg1 = /str/; // /str/
let reg2 = new RegExp(str); // /text/
修饰符
i
:不区分大小写 (ignoreCase)m
:换行匹配 (multiline)g
:全局匹配 (global)
使用简洁语法创建正则时,修饰符跟在最后;使用构造函数创建正则时,修饰符作为第二参数
i
:不区分大小写 (ignoreCase)
默认区分大小写,设置 i
后不区分大小写
let reg = /Text/;
let str = 'This is a text';
console.log(str.match(reg)); // null - 返回 null 表示匹配失败
let reg = /Text/i; // 不区分大小写
let str = 'This is a text';
console.log(str.match(reg)); // [ 'text', index: 10, input: 'This is a text', groups: undefined ]
m
:换行匹配 (multiLine)
默认是单行匹配,设置 m
后能换行匹配
let reg = new RegExp('^Text'); // 检查字符串前缀是否为 Test
let str = 'This is a \nText and';
console.log(str.match(reg)); // null - 返回 null 表示匹配失败
let reg = new RegExp('^Text', 'm'); // 换行匹配
let str = 'This is a \nText and';
console.log(str.match(reg)); // [ 'Text', index: 11, input: 'This is a \nText and', groups: undefined ]
g
:全局匹配 (global)
默认只匹配一个,设置 g
能匹配多个
let reg = new RegExp('text');
let str = 'This is a text and text and text';
console.log(str.match(reg)); // ["text", index: 10, input: "This is a text and text and text", groups: undefined]
let reg = new RegExp('text', 'g');
let str = 'This is a text and text and text';
console.log(str.match(reg)); // ["text", "text", "text"]
正则的方法
- 正则表达式
reg
调用方法 - 传入的参数是字符串
str
①
test()
:用于判断参数str
中是否含有匹配正则的子字符串
- 返回值:含有匹配正则的子字符串则返回
true
;否则返回false
// demo: 匹配 ^a
let reg1 = /^a/g; // ^ 有特殊意义
let reg2 = /\^a/g; // 匹配 ^ 需要使用转义符 \ 转义
let str = 'bb^acc';
console.log(reg1.test(str)); // false - 匹配失败
console.log(reg2.test(str)); // true - 匹配成功
②
exec()
:获取第 1 个匹配正则的子字符串的信息
- 返回一个数组,存放匹配正则的子字符串的信息;如果没有找到匹配的子字符串,则返回
null
let reg1 = /superman/;
let reg2 = /monster/;
let str = 'hello superman';
console.log(reg1.exec(str)); // [ 'superman', index: 6, input: 'hello superman', groups: undefined ]
console.log(reg2.exec(str)); // null
- 匹配正则的子字符串的信息包括:子字符串、开始下标、字符串
str
、所在分组
字符串的方法
- 字符串
str
调用方法 - 传入的参数是正则表达式
reg
①
match()
:获取所有匹配正则的子字符串组成的数组 / 获取第 1 个匹配正则的子字符串的信息
- 如果
reg
没有设置全局修饰符g
:获取第 1 个匹配正则的子字符串的信息
let reg1 = /superman/;
let reg2 = /monster/;
let str = 'hello superman';
console.log(str.match(reg1)); // [ 'superman', index: 6, input: 'hello superman', groups: undefined ]
console.log(str.match(reg2)); // null
- 如果
reg
有设置全局修饰符g
:获取所有匹配正则的子字符串组成的数组
let reg1 = /superman/g;
let reg2 = /monster/g;
let str = 'hello superman';
console.log(str.match(reg1)); // [ 'superman' ]
console.log(str.match(reg2)); // null
②
search()
:获取第 1 个匹配正则的子字符串的开始下标
let reg = /superman/;
let str = 'hello superman';
console.log(str.search(reg)); // 6
③
split()
:以匹配正则的子字符串为分界点,把字符串转成数组
let reg = /superman/;
let str = 'hello superman superman aaa';
console.log(str.split(reg)); // [ 'hello ', ' ', ' aaa' ]
④
replace()
:找到匹配正则的子字符串,用第 2 参数将其替换
let reg1 = /man/; // 替换匹配正则的第 1 个子字符串
let reg2 = /man/g; // 替换匹配正则的所有子字符串
let str = 'hello superman superman';
console.log(str.replace(reg1, 'women')); // hello superwomen superman
console.log(str.replace(reg2, 'women')); // hello superwomen superwomen
特殊语法
特殊字符
- 正则表达式 = 普通字符 + 特殊字符
- 普通字符:
字母
(abcABC)、数字
(123)、_
、$
特殊字符:\
、[]
、{}
、()
、^
、$
、*
、?
、+
、|
、.
… - 普通字符可以直接使用(上面的例子都是使用普通字符)
如果要匹配特殊字符,得使用转义符\
修饰,因为特殊字符在正则中有特殊意义
// 匹配 ^a
let reg = /\^a/g; // ^ 有特殊意义,匹配 ^ 需要使用转义符 \ 转义
let str = 'bb^acc';
console.log(str.match(reg)) // [ '^a' ]
预定义的特殊字符:
\t
水平制表符、\n
换行符、\f
换页符、\b
退格符…
界定符
检查前后缀
- 检查前缀用
^
,如:/^abc/
检查字符串的前缀是否为abc
- 检查后缀用
$
,如:/xyz$/
检查字符串的后缀是否为xyz
let str = 'sdf';
let reg = /^s/;
console.log(reg.test(str)); // true
检查其后是否紧跟着指定字符串
(?=n)
:匹配到后面紧跟着字符n
的字符串(?!n)
:匹配到后面没有紧跟着字符n
的字符串
let str = 'abcd';
let reg = /bc(?=d)/g; // 找到后面跟着 d 的字符串 bc
console.log(str.match(reg)); // [ 'bc' ]
字符集 []
简单类
- 通过
[]
包裹住,来表示这几个字母组成的一个简单集合
如:[abDF45]
表示由abDF45
6 个字符组成的一个集合
// 在 `str` 中找到第 1 个在集合 `[gbk]` 中的字符
let str = 'abcdefg';
let reg = /[gbk]/g;
console.log(str.match(reg)); // [ 'b', 'g' ]
范围类
- 通过
[小字符-大字符]
组成的一个范围集合(大小指的是 ASCII 码大小)
如:[a-z]
表示小写字母集合、[A-Z]
表示大写字母集合、[0-9]
表示数字集合
let str = 'abcdefg';
let reg = /[f-i]/g;
console.log(str.match(reg)); // [ 'f', 'g' ]
- 要按照字符编码集从小到大写 eg:
[A-z]
;不能从大到小写 eg:[a-Z]
- 特殊的字符集:
[\u4e00-\u9fa5]
表示中文集
负向类
- 在
[^字符]
内部添加^
前缀,表示不包含该集合的字符集
如:[^abc]
表示不包含abc
的集合,[^ab89CD]
表示不包含ab89CD
这 6 个字符的集合
let str = 'abcdef';
let reg = /[^abc]/g;
console.log(str.match(reg)); // [ 'd', 'e', 'f' ]
组合类
- 将几个集合拼接在一起,表示一个组合的集合
如:[a-zA-Z0-9]
表示大小写字母以及数字的集合
let str = '0';
let reg = /[0-9a-z]/;
console.log(reg.test(str)); // true
注意:在
[]
内,无论写多少个字符,只会匹配其中一个
元字符
就是特殊的转义字符,把一些字母转成特殊意义的字符
.
→[^\n\r]
:除了换行和回车之外的任意字符\d
→[0-9]
:数字字符( digit 数字 )\D
→[^0-9]
:非数字字符\s
→[\t\n\f\r]
:空白字符\S
→[^\t\n\f\r]
:非空白字符\w
→[a-zA-Z_0-9]
:字母数字下划线\W
→[^a-zA-Z_0-9]
:非字母数字下划线
let str = 'sdf';
let reg = /\W/;
console.log(reg.test(str)); // false
量词 {}
-
用于设置匹配的字符个数
-
默认贪婪匹配,即尽量往字符个数多的匹配;在量词后加
?
,则变为惰性匹配,即尽量往字符个数少的匹配 -
重复书写某个规则时,可以用量词代替。eg:匹配 10 个数字,
/\d\d\d\d\d\d\d\d\d\d/
→/\d{10}/
普通写法
{n}
:n 个{n,m}
:n ~ m 个,闭区间 [n, m](注意:n,m
的,
后面不要空格){n,}
:n ~ 无数个,半开半闭区间 [n, ∞)
let str = 'a b a bb a bbb a bbbb';
let reg1 = /b{2,4}/g; // 贪婪匹配
console.log(str.match(reg1)); // ["bb", "bbb", "bbbb"]
let reg2 = /b{2,4}?/g; // 惰性匹配
console.log(str.match(reg2)); // ["bb", "bb", "bb", "bb"]
特殊写法
{0,1}
→?
{0,}
→*
{1,}
→+
let str = 'babba'; // 5 个字符
let reg1 = /b?/g;
console.log(str.match(reg1)); // [ 'b', '', 'b', 'b', '', '' ] → 6 个元素,按匹配元素分割开了
let reg2 = /b*/g;
console.log(str.match(reg2)); // [ 'b', '', 'bb', '', '' ] → 5 个元素,也是按匹配元素分割开了
let reg3 = /b+/g;
console.log(str.match(reg3)); // ["b", "bb"]
子项 ()
可以用 ()
将部分正则括住,这样在使用 match
/ exec
做匹配时,能获取指定字符开头的数据
let str = "abcd12ef";
let reg = /d(\d+)/g; // 获取 d 开头的数字字符串
console.log(str.match(reg)); // [ 'd12' ]
子项的反引用
格式:\num
;num
为子项的序号
let str = "ccsdbbcc99d";
let reg = /([a-z])\1/g; // 获取 XX 格式的子字母字符串
console.log(str.match(reg)); // [ 'cc', 'bb', 'cc' ]
上面 \1
表示复用第 1 个子项 ([a-z])
的结果
获取 |
在正则中,
|
表示或者
let str = "adcd12ef";
let reg = /ad|cd/g;
console.log(str.match(reg)); // [ 'ad', 'cd' ]
可以与子项结合使用:
let str = "adcd12ef";
let reg = /(a|c)d/g;
console.log(str.match(reg)); // [ 'ad', 'cd' ]
在字符集中,
|
是普通的竖线
let str = "adcd1|d2ef";
let reg = /[a|c]d/g; // `[a|c]` 表示 `a`、`|`、`b` 中的任意 1 个
console.log(str.match(reg)); // [ 'ad', 'cd', '|d' ]
demo
demo 1:手机号( 11 位数字、第一位是 1 )
let reg = /^1\d{10}$/;
let num = 13188886666;
if (reg.test(num)) {
console.log('成功');
} else {
console.log('失败');
}
demo 2:QQ 邮箱
let eMail = /^\d{6-10}@q{2}\.com$/;
.
在正则中有特殊意义,所以需要转义
demo 3:日期格式转换
function formatDate(date, fmt) {
// 年
let reg = /Y+/;
if (reg.test(fmt)) {
let str = fmt.match(reg)[0]; // 获取年份的格式
// 使用 str.substring(start, end) 控制年份的表示长度与格式一致
let year = (date.getFullYear() + '').substring(4 - str.length);
fmt = fmt.replace(str, year); // 用年份替换格式字符串
}
// 月日时分秒
let obj = {
'M+': date.getMonth() + 1,
'D+': date.getDate(),
'h+': date.getHours(),
'm+': date.getMinutes(),
's+': date.getSeconds()
}
for (let key in obj) {
let reg = new RegExp(key);
if (reg.test(fmt)) {
let str = fmt.match(reg)[0]; // 获取对应时间的格式
fmt = fmt.replace(str, toTwo(obj[key])); // 用时间替换格式字符串
}
}
return fmt;
}
function toTwo(num) {
return (num > 10 ? '' : '0') + num;
}
let date = new Date();
let fmt = 'YYYY-MM-DD hh:mm:ss';
console.log(formatDate(date, fmt));