本文最后更新于 2021年4月4日 晚上
这个是跟着 FCC 中 JS 的正则表达式习题练习时候的记录.
正则表达式习题
写表达式的语法是这样的: /表达式/
, 其结果是生成一个正则表达式对象, 在该对象上即可调用若干方法进行对应操作.
默认情况下是大小写敏感的, 比如搜索 Hello
和 hello
, 可能出现不同结果.
在正则表达式中可以使用 |
操作符, 比如 /a|b/
表示找 "a"
或 "b"
.
在表达式尾部的 /
后面可以接选项, 如果需要忽略大小写, 则在尾部追加 i
, 比如 /dog/i
.
String
对象提供了一个 match
方法, 可以直接在该方法中传入表达式, 返回的是搜索结果数组:
1 2
| const occ = 'Hello World'.match(/o/i); console.log(occ.length);
|
- 如果没有指定参数, 则默认只搜索最先找到的一个. 如果想搜索多个, 则可以使用
g
参数:
1 2
| const occ = 'Hello World'.match(/o/ig); console.log(occ.length);
|
- 使用
.
来匹配任意字符:
1 2
| const occ = 'Hello World'.match(/l./ig); console.log(occ);
|
可以看到这里实际没有找完, 因为 lo
没有被找到.
- 除了使用
.
来匹配外, 还可以使用 []
来包含需要的字符:
1 2
| const occ = 'Hello World'.match(/l[lod]/ig); console.log(occ);
|
可见, 仍然没有在第一个单词中找到 lo
, 即使前面指定过找 lo
字符串(/l[lod]/
).
- 除了列举, 还可以使用
-
来指定范围内的字符:
1 2
| const occ = 'Hello World'.match(/l[a-p]/ig); console.log(occ);
|
- 也可以列举数字:
1 2
| const occ = 'Hello World 123456'.match(/[a-z0-9]/ig); console.log(occ);
|
- 上述都是在将自己想要的字符进行列举, 而如果想列举自己不想要的字符, 则可以在模式开头添加一个
^
:
1 2
| const occ = 'Hello World 123456 I hava a dream'.match(/[^a-p0-9]/ig); console.log(occ);
|
即会去找除了 0 到 9 数字, 以及 a 到 p 字母外的任意字符, 比如空格.
- 使用
+
(一个或多个)来指定查找字符或重复出现的字符:
1 2
| const occ = 'Hello World'.match(/l+/ig); console.log(occ);
|
- 使用
*
(0 个或多个) 来匹配重复字符:
1 2
| const occ = 'Heello World, and he says gotohell.'.match(/h*e/ig); console.log(occ);
|
上面的正则表达式含义就是找 0 到 多个 h 接一个 e 的情况, 忽略大小写和全局查找.
- 如果想要找一段文本, 中间是任意字符, 这样叫贪心查找, 即总是努力寻找到最长的字符串匹配值:
1 2
| const occ = 'Heoello World, and he says gotohell.'.match(/h[a-z]*o/ig); console.log(occ);
|
可以看到搜索时并没有输出 Heo
, 而是输出的更长的 Heoello
- 和贪心查找相对的就是懒查找, 在贪心查找的
*
后面添加一个 ?
即可, 它就去找能匹配的最短字符串:
1 2
| const occ = 'Heoello World, and he says gotohell.'.match(/h[a-z]*?o/ig); console.log(occ);
|
- 前面看到, 如果
^
用在集合 []
内, 表示排除. 而如果是用在顶层, 则表示字符串开头:
1 2
| const occ = 'Marray says "I\'m Marray".'.match(/^Marray/ig); console.log(occ);
|
可见只会搜索到开头的那个 Marray.
- 有开头就有结尾, 字符串结尾使用
$
表示:
1 2
| const occ = 'Hello World and welcome to our new world'.match(/World$/ig); console.log(occ);
|
- 有的时候通过字符集
[]
来枚举各种情况很费劲, 比如 [a-zA-Z0-9]
, 而 js 内提供了这类字符集的特殊写法:
比如使用 \w
来代表字母或数字:
1 2
| const occ = 'Hello World1'.match(/W\w*/ig); console.log(occ);
|
指定的是忽略大小写, 全局查找的, 以 W
开头的且包含 0 到多个字母和数字的连续字符的字符串, 通过 \w
来代表 [a-zA-Z0-9]
.
- 有表达 “字母或数字” 的符号, 就有表达 “非字母或数字” 的符号, 这个就是
\W
:
1 2
| const occ = 'Hello W@#$orld1'.match(/W\W*/ig); console.log(occ);
|
匹配所有数字, 使用 \d
(即[0-9]
), 非数字使用 \D
(即 [^0-9]).
使用 \s
代表空白字符, 可以认为它代表的是 [ \r\t\f\n\v]
, 即空格或回车换行等, 非空白就是 \S
.
可以使用 {lower, upper}
这样的形式来指定匹配次数, 比如:
1 2
| const occ = 'Hello W@#$orld1 H1 H12 H123 H123456'.match(/H\w{3,5}/ig); console.log(occ);
|
找以 H 开头不区分大小写的连续字符串, 后面跟的连续字符串最小长度是 3, 最大长度是 5.
- 在使用匹配次数操作符的时候也可以不指定上界:
1 2
| const occ = 'Hello W@#$orld1 H1 H12 H123 H123456'.match(/H\w{3,}/ig); console.log(occ);
|
- 当然可以严格限制匹配的字符个数:
1 2
| const occ = 'Hello W@#$orld1 H1 H12 H123 H123456'.match(/H\w{3}/ig); console.log(occ);
|
- 如果
?
没有用在懒搜索中, 则表示的是 0 个或一个:
1 2
| const occ = 'Hello W@#$orld1 H23 H12'.match(/H\w?/ig); console.log(occ);
|
- 在一个字符串中仅向前搜索而不产生对应模式的匹配结果, 则可以使用 LookAhead, 它有两种形式:
positive lookahead
: will look to make sure the element in the search pattern is there, but won’t actually match it.
语法是 (?=...)
, 其中 ...
位置就是想要判断的模式.
1 2
| const occ = 'Hello World'.match(/H(?=e)/ig); console.log(occ);
|
即匹配以 H 开头的, 如果 H 之后是 e, 则匹配成功, 相当于加一个条件, 但不将条件模式加入到匹配结果, 只看它在不在.
negative lookahead
: will look to make sure the element in the search pattern is not there.
1 2
| const occ = 'Hello World'.match(/H(?!o)/ig); console.log(occ);
|
即匹配以 H 开头的, 且判断 H 后续是否包含有 o, 如果有则匹配失败, 否则匹配成功.
- 在写模式的时候有很多模式都是重复的, 如果复制粘贴一串来看肯定很长又不好看, 最好的办法还是使用
capture groups
来写可重用的模式, 实际语法就是 ()
括起来, 在后面需要重复的时候只用指定类似 \1
即可, 其中 1 代表的是第一个 group:
1 2
| const occ = "regex regex".match(/(\w+)\s\1/ig); console.log(occ);
|
- 可以使用
$1
这样的语法来访问正则表达式搜索的结果:
1 2
| const occ = "Hello World".replace(/(\w+)\s(\w+)/, '$2 $1'); console.log(occ);
|
- 使用
trim
操作符移除字符串首尾的空白符:
1 2
| const occ = "\r\n Hello World\r\n".trim(); console.log(occ);
|