1.RegExp对象的函数和属性
1.1 基本属性(参考自W3school)
| 修饰符 | 描述 |
|---|---|
i | 执行对大小写不敏感的匹配 |
g | 执行全局匹配(查找所有匹配而非在找到第一个匹配后停止) |
m | 执行多行匹配 |
| 属性 | 描述 | 是否只读 |
|---|---|---|
global | RegExp 对象是否具有标志 g | 只读 |
ignoreCase | RegExp 对象是否具有标志 i | 只读 |
multiline | RegExp 对象是否具有标志 m | 只读 |
source | 正则表达式的源文本,不包括正则表达式直接量使用的定界符,也不包括修饰符 g、i、m | 只读 |
lastIndex | 一个整数,标示开始下一次匹配的字符位置 | 非只读属性,可以修改 |
// 说明:两种创建正则对象的写法是等价写法,区别在于使用构造函数创建正则对象可以传递参数,而简写方式不可以。后文中的案例都会使用简写方式
const regExp = new RegExp('^hello$','gim')
const newRegExp = /^hello$/gim
console.log(regExp) // 输出 /^hello$/gim
console.log(newRegExp) // 输出 /^hello$/gim
// 简单输出测试RegExp对象的基本属性
const regExp = /^hello$/gim
console.log(regExp) // 输出 /^hello$/gim
console.log(regExp.global) // 输出 true
console.log(regExp.ignoreCase) // 输出 true
console.log(regExp.multiline) // 输出 true
console.log(regExp.source) // 输出 "^hello$"
console.log(regExp.lastIndex) // 输出 0
1.2 test函数
- 可以用来校验某个字符串是否符合某个格式
- 返回一个
boolean值
// 校验一个字符串是否为11位合法电话号码
const regExp = /^[1][3,4,5,7,8][0-9]{9}$/
const phone = '15889912345'
console.log(regExp.test(phone)) // 输出 true
1.3 exec函数
- 可以用来在字符串中截取特定匹配项
- 如果字符串中有符合正则表达式的匹配项,返回一个匹配数组,无则返回
null - 正则表达式不加
g修饰符,进行懒匹配,第一次有匹配项的时候立刻返回一个匹配数组 - 正则条件加
g修饰符,进行全局匹配,可以通过循环调用exec函数,逐次返回各个匹配数组
// 懒匹配,截取一句话里的第一个英文单词
const regExp = /[a-z]+/i
const words = 'Hello World'
const result = regExp.exec(words)
console.log(result) // 输出 ["Hello", index: 0, input: "Hello World"]
console.log(result[0]) // 输出 Hello
| 匹配数组的属性 | 描述 |
|---|---|
index | 匹配字符串的在原字符串中的起始下标 |
input | 原字符串 |
result[0] | 原字符串中第一个匹配整个正则表达式的字符串 |
// 全局匹配,截取一句话里的每个英文单词
const regExp = /[a-z]+/ig
const words = 'Hello World'
let result = null
while ((result = regExp.exec(words)) != null) {
console.log('result:', result)
console.log(`result[0]: ${result[0]}`)
console.log(`regExp.lastIndex: ${regExp.lastIndex}`)
}
console.log(`重置后的regExp.lastIndex: ${regExp.lastIndex}`)
// 控制台依次输出
result: ["Hello", index: 0, input: "Hello World"]
result[0]: Hello
regExp.lastIndex: 5
result: ["World", index: 6, input: "Hello World"]
result[0]: World
regExp.lastIndex: 11
重置后的regExp.lastIndex: 0
结论:只有在全局匹配的模式下,lastIndex会在exec函数的执行后变化,记录着原字符串中开始下一次匹配的字符下标,直到exec函数无匹配项,返回null的时候,lastIndex才会自动重置为0
1.4 RegExp.$n属性(只读)
- 目标匹配项的正则子表达式需要加括号,代表一个分组
- 在每次
exec函数返回的匹配数组中,可以获取对应匹配项 - n的范围是[1,9]的正整数,即
RegExp.$1直到RegExp.$9
// 截取时间字符串里的时分秒信息,分组1是([0-1]?[0-9]|2[0-3]),用来截取小时,分组2是([0-5][0-9]),用来截取分钟,分组3是([0-5][0-9]),用来截取秒
const regExp = /([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])/
const dateTime = '2018-08-03 23:15:50'
const result = regExp.exec(dateTime)
console.log(result) // 输出 ["23:15:50", "23", "15", "50", index: 11, input: "2018-08-03 23:15:50"]
console.log(result[1]) // 输出 23
console.log(result[2]) // 输出 15
console.log(result[3]) // 输出 50
console.log(RegExp.$1) // 输出 23
console.log(RegExp.$2) // 输出 15
console.log(RegExp.$3) // 输出 50
输出数据说明:
| result属性 | RegExp属性 | 描述 |
|---|---|---|
result[1] | RegExp.$1 | 匹配正则表达式的第一个分组的字符串 |
result[2] | RegExp.$2 | 匹配正则表达式的第二个分组的字符串 |
result[3] | RegExp.$3 | 匹配正则表达式的第三个分组的字符串 |
正则表达式说明:
| 表达式 | 作用 |
|---|---|
| ( ) | 1.在被修饰匹配次数的时候,括号中的表达式可以作为整体被修饰 2.取匹配结果的时候,括号中的表达式匹配到的内容可以被单独得到 |
结论:由括号表达式的第2点作用和以上例子可以知道,在exec函数执行结果有返回匹配数组的情况下,正则表达式的每个分组都对应一个匹配数组中的匹配子串,可以被单独取得。
(1)当n等于[1,9]的任一正整数时,RegExp.$n对应匹配数组中的第n个匹配子项,等价于result[n]
(2)当n>9的时候,只能通过result[n]来取匹配子项
2.String对象的函数
2.1 replace函数
- 用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串
- 函数的第二个参数replacement可以为字符串或函数(函数必须有返回值,否则替换字符串会变成
undefined) 中的 $字符具有特定的含义。如下表所示,它说明从模式匹配得到的字符串将用于替换
| 字符 | 替换文本 |
|---|---|
$1、$2、...、$99 | 与 regexp 中的第1 到第 99 个子表达式相匹配的文本 |
$& | 与 regexp 相匹配的子串 |
$` | 位于匹配子串左侧的文本 |
$' | 位于匹配子串右侧的文本 |
$$ | 直接量符号,代表转义出$字符 |
基本用法:
// 把一句话中的非法关键字替换为"**"
let words = '他是一个大笨蛋!'
let result = words.replace(/笨蛋/g, '**')
console.log(result) // 输出 他是一个大**!
// 在单词"friend"左边插入单词"best"
words = 'Hello, my friend'
result = words.replace(/friend/, 'best $&')
console.log(result) // 输出 Hello, my best friend
// $`和$'没想到什么实际应用的场景
words = 'Hello World'
result = words.replace(/Hello\s/, `$'`)
console.log(result) // 输出 WorldWorld
result = words.replace(/\sWorld/, '$`')
console.log(result) // 输出 HelloHello
进阶用法:
// 驼峰命名转横杠命名
const camelParamName = 'myCompanyName'
let result = camelParamName.replace(/([A-Z])/g, '-$1').toLowerCase()
console.log(result) // 输出 my-company-name
result = camelParamName.replace(/[A-Z]/g, '-$&').toLowerCase()
console.log(result) // 输出 my-company-name
结论:
(1)正则里有用括号分组才可以使用$1、$2、...、$99去取匹配文本
(2)$1和$&在非全局模式会获得第一个匹配的文本,在全局模式会获得所有匹配的文本(在此例子中会匹配myCompanyName中的C和N字符)
// 横杠命名转驼峰命名
const dashParamName = 'my-company-name'
const result = dashParamName.replace(/-[a-z]/g, matched => {
console.log(`matched: ${matched}`)
return matched[1].toUpperCase()
})
console.log(`result: ${result}`)
// 控制台依次输出
matched: -c
matched: -n
result: myCompanyName
执行顺序说明(个人理解):
(1)执行replace函数
(2)执行第一次正则匹配,获得匹配子串'-c'
(3)执行第一次replacement回调函数,matched='-c',matched[1]='c',matched[1].toUpperCase() = 'C'然后返回'C'
(4)拼接字符串'myC'
(5)执行第二次正则匹配,获得匹配子串'-n'
(6)执行第二次replacement回调函数,matched='-n',matched[1]='n',matched[1].toUpperCase() = 'N'然后返回'N'
(7)拼接字符串'myCompanyN'
(8)执行第三次正则匹配,无匹配项,返回null,停止匹配
(9)拼接并返回字符串'myCompanyName',结束replace函数
结论:全局模式下,replacement函数执行次数等于正则匹配子串个数,matched就是匹配子串,每次进入replacement函数,对匹配子串进行处理后再返回(注意:replacement函数必须有返回值,否则替换文本会变成undefined,replace函数会返回一个经过以上执行顺序处理后的新字符串)
2.2 split函数
- 把一个字符串分割成字符串数组
|参数 |描述|
|---- |:----|
|
separator|必需。字符串或正则表达式,从该参数指定的地方分割 stringObject| |howmany|可选。该参数可指定返回的数组的最大长度。如果设置了该参数,返回的子串不会多于这个参数指定的数组。如果没有设置该参数,整个字符串都会被分割,不考虑它的长度|
// 把一个日期时分秒字符串切割成年、月、日、时、分、秒数组
const regExp = /-|\s|:/
const dateTime = '2018-08-06 16:20:00'
let result = dateTime.split(regExp)
console.log(result) // 输出 ["2018", "08", "06", "16", "20", "00"]
// 把一个日期时分秒字符串切割成年、月、日数组
result = dateTime.split(regExp, 3)
console.log(result) // 输出 ["2018", "08", "06"]
2.3 match函数
- 可以用来在字符串中截取特定匹配项
- 正则表达式不加
g修饰符,进行懒匹配,第一次有匹配项的时候立刻返回一个匹配数组,无则返回null - 正则条件加
g修饰符,进行全局匹配,有匹配返回所有匹配子串合并后的数组,无则返回null
// 懒匹配,获取算式中的第一个数字
let regExp = /\d/
const equation = '1+2=3'
let result = equation.match(regExp)
console.log(result) // 输出 ["1", index: 0, input: "1+2=3"]
// 全局匹配,获取算式中的所有数字
regExp = /\d/g
result = equation.match(regExp)
console.log(result) // 输出 ["1", "2", "3"]
结论:
(1) 非全局匹配模式下,match函数的返回值和exec函数的一样
(2) 全局匹配模式下,match函数只返回所有匹配子串合并后的数组,不会返回匹配项的详细信息。因此,如果需要每个匹配项的详细信息,就需要循环调用exec函数