# JavaScript 正则表达式
# 前言
;MDN (opens new window) 对正则表达式有更为详细的描述,此文仅是学习正则表达式过程中的记录和发散,相关的内容后面会逐步进行完善。
# 方法
# test
;test (opens new window) 用来检查字符串是否与正则表达式相匹配,返回布尔值。
/hello/.test('hello_world') // true
来看一个特殊情况。
const reg = /hello/
reg.test('hello_world') // true
reg.test('say_hello') // true
const reg = /hello/g
reg.test('hello_world') // true
reg.test('say_hello') // false
reg.test('hello_regexp') // true
你应该知道的是,每个正则表达式都有一个 lastIndex (opens new window) 属性,用来指定下一次匹配的起始索引,可读也可写,默认值为0
(表示从字符串头部开始匹配)。但是一般不会起作用,只有在正则表达式开启了全局匹配g
时,lastIndex
才会生效。
以上第一个正则表达式未开启全局匹配,lastIndex
始终不生效,每次执行test
时都是从字符串的头部开始匹配,所以都会输出true
。而当开启全局匹配时,执行第一个test
匹配成功输出true
,此时会将lastIndex
更新为5
,以便下一次匹配,而执行第二个test
时,由于lastIndex
为5
(即从ello
开始匹配),将匹配失败输出false
。而匹配失败后,lastIndex
将被重置为0
,所以第三个test
又输出true
。
因此若要在开启全局匹配下输出一致,可修改lastIndex
属性(4
表示从hello
开始匹配)。
const reg = /hello/g
reg.test('hello_world') // true
reg.lastIndex = 4
reg.test('say_hello') // true
reg.lastIndex // 9
# exec
;exec (opens new window) 用于对字符串执行一次搜索匹配,返回一个结果数组或null
。
其中数组中包括[0]
(匹配的完整字符串)、[1]...[n]
(捕获的分组)、index
(匹配的内容在原字符串中的索引)、input
(原字符串)、group
(ES6
的具名组)。
const reg = /h(e)ll(o)/i
const str = 'Hello foo, hEllo bar, heLlo baz'
reg.exec(str) // ["Hello", "e", "o", index: 0, input: "Hello foo, hEllo bar, heLlo baz", groups: undefined]
注意exec
也与test
类似,开启全局匹配g
后lastIndex
才会生效,开启后exec
可以获取单个字符串中的多次匹配结果。并且与test
类似,exec
若匹配失败,lastIndex
也会归0
。
const reg = /h(e)ll(o)/ig
const str = 'Hello foo, hEllo bar, heLlo baz'
var res = null
while (res = reg.exec(str)) {
console.log(res)
// ["Hello", "e", "o", index: 0, input: "Hello foo, hEllo bar, heLlo baz", groups: undefined]
// ["hEllo", "E", "o", index: 11, input: "Hello foo, hEllo bar, heLlo baz", groups: undefined]
// ["heLlo", "e", "o", index: 22, input: "Hello foo, hEllo bar, heLlo baz", groups: undefined]
}
# 字符串方法
;ES6
将String.prototype
中的四个方法search
、split
、replace
、match
在语言内部都调用了RegExp.prototype
上的方法,例如String.prototype.search
调用RegExp.prototype[Symbol.search]
。
另外若方法的参数为对象,都会存在隐式类型转换。
const str = 'foo, bar, baz'
const reg = {
toString() {
return 'baz'
}
}
str.search(reg) // 10
str.split(reg) // ["foo, bar, ", ""]
str.replace(reg, 'yes') // foo, bar, yes
str.match(reg) // ["baz", index: 10, input: "foo, bar, baz", groups: undefined]
# search
;search (opens new window) 用于返回正则表达式在字符串中首个匹配项的索引,若未匹配则返回-1
。
'hello world'.search(/world/) // 6
'hello world'.search(/say/) // -1
'hello world'.search('llo') // 2
# split
;split (opens new window) 用于分割字符串为数组。
其中第一个参数为字符串或者正则表达式,第二个参数用于限制分割后的数组长度。
'say hello world'.split(/[er]/) // ["say h", "llo wo", "ld"]
'say hello world'.split(' ') // ["say", "hello", "world"]
'say hello world'.split(' ', 1) // ["say"]
# replace
;replace (opens new window) 用于替换字符串中的字符为另一些字符,原字符串不变,返回一个新的字符串。
'hello world'.replace('world', 'regexp') // hello regexp
'hello world'.replace(/[er]/g, 'm') // hmllo womld
另外第二个参数可以为一些特殊变量名。
$&
:匹配的字符串&`
:匹配结果前面的内容&'
:匹配结果后面的内容$n
:分组捕获,捕获的第n
组内容$$
:符号$
&<name>
:具名组捕获,捕获的分组内容
'hello_world'.replace(/world/, '$&') // hello_world
'hello_world'.replace(/world/, '$`') // hello_hello_
'hello_world'.replace(/world/, "$'") // hello_
'hello_world'.replace(/(world)/, '$1') // hello_world
'hello_world'.replace(/world/, '$$') // hello_$
'hello_world'.replace(/(?<key>world)/, '$<key>') // hello_world
# match
;match (opens new window) 用于返回一个字符串匹配正则表达式的结果。
注意若未开启全局匹配g
,将返回第一个匹配结果和捕获组(等价于exec
)。若开启全局匹配,将只返回匹配的所有结果。
const reg = /h(e)ll(o)/i
const rege = /h(e)ll(o)/ig
const str = 'Hello foo, hEllo bar, heLlo baz'
str.match(reg) // ["Hello", "e", "o", index: 0, input: "Hello foo, hEllo bar, heLlo baz", groups: undefined]
str.match(rege) // ["Hello", "hEllo", "heLlo"]
# 修饰符
# i
忽略大小写。
/hello/.test('Hello world') // false
/hello/i.test('Hello world') // true
正则表达式是否设置i
修饰符。
const reg = /a/i
reg.ignoreCase // true
# g
全局匹配。
'hello'.replace(/l/, 'm') // hemlo
'hello'.replace(/l/g, 'm') // hemmo
正则表达式是否设置g
修饰符。
const reg = /a/g
reg.global // true
# m
多行匹配。
const str = 'hello \nworld'
/^world/.test(str) // false
/^world/m.test(str) // true
world
位于第二行行首,指定多行匹配m
后会被匹配上
正则表达式是否设置m
修饰符。
const reg = /a/m
reg.multiline // true
# s
正则表达式中.
不匹配\n
,ES2018
引入了s
修饰符,可以匹配任何单个字符。
const str = 'hello\nworld'
/hello.world/.test(str) // false
/hello.world/s.test(str) // true
/hello[^]world/.test(str) // true
正则表达式是否设置s
修饰符。
const reg = /a/s
reg.dotAll // true
# u
;Unicode
模式,用于正确识别大于0xffff
的字符。
/^.$/.test('𠮷') // false
/^.$/u.test('𠮷') // true
正则表达式是否设置u
修饰符。
const reg = /a/s
reg.unicode // true
# y
粘连模式,要求每次都是从剩余字符串的头部开始匹配。
const str = 'aaa_aa_a'
const g = /a+/g
const y = /a+/y
g.exec(str) // ["aaa"]
g.exec(str) // ["aa"]
y.exec(str) // ["aaa"]
y.exec(str) // null
以上粘连模式中,第一次exec
匹配后lastIndex
为3
,第二次exec
匹配时,剩余的字符串为_aa_a
,而粘连模式要求从剩余字符串的头部开始(即/a+/y
等价于/^a+/g
)匹配,因此匹配失败,返回null
并且lastIndex
重置为0
。
const str = 'aaa_aa_a'
const y = /a+_/y
y.exec(str) // ["aaa_"]
y.exec(str) // ["aa_"]
正则表达式是否设置y
修饰符。
const reg = /a/y
reg.sticky // true
# 🎉 写在最后
🍻伙伴们,如果你已经看到了这里,觉得这篇文章有帮助到你的话不妨点赞👍或 Star (opens new window) ✨支持一下哦!
手动码字,如有错误,欢迎在评论区指正💬~
你的支持就是我更新的最大动力💪~
GitHub (opens new window) / Gitee (opens new window)、GitHub Pages (opens new window)、掘金 (opens new window)、CSDN (opens new window) 同步更新,欢迎关注😉~