这里是对正则表达式的思考,源自一个题目:
完成一个 extractStr 函数,可以把一个字符串中所有的 : 到 . 的子串解析出来并且存放到一个数组当中,例如:
extractStr('My name is:Jerry. My age is:12.') // => ['Jerry', '12']
注意,: 和 . 之间不包含 : 和 .。也即是说,如果 ::abc..,则返回 [‘abc’]。
他给出的答案是1
2
3
4const extractStr = (str) => {
const ret = str.match(/:([^:\.])*?\./g) || []
return ret.map((subStr) => subStr.replace(/[:\.]/g, ''))
}
首先正则表达式匹配到的结果是[‘:Jerry.’,’:12.’],然后再对数组进行操作,去掉 :
和 .
。
这样做不就多了一步了嘛,其实我们完全可以用正则来一步解决1
2
3
4
5
6
7const extractStr = (str) => {
const reg = /(?<=:)(\w*)(?=\.)/g;
const ret = str.match(reg) || []
return ret;
}
var str = 'My name is:Jerry. My age is:12.'
extractStr(str);
这样一步,就能得到我们的结果['Jerry','12']
,而且有多余的 :
或者 .
也可以匹配到正确的结果。接下来解释一下这个正则表达式。/(?<=:)(\w*)(?=\.)/g;
我们先看大部分正则都有的部分(\w*)
,\w*
就是匹配任意字符串0个或多个,()
的意思则是捕获,即记住这个捕获的内容。所以合起来就是匹配任意字符串0个或多个并且记住匹配项。
然后是正则表达式 /.../g
后面的’g’,这是正则表达式标志:
标志 | 描述 |
---|---|
g | 全局搜索。 |
i | 不区分大小写搜索。 |
m | 多行搜索。 |
y | 执行“粘性”搜索,匹配从目标字符串的当前位置开始,可以使用y标志。 |
使用 g
之后,不会因为匹配到一个匹配项就停下,而是继续搜索。
接下来就是两个不常见的 (?<=:)
和 (?=\.)
首先解释一下名字 (?<=:)
的意思是反向肯定查找,而(?=\.)
的意思就是正向肯定查找。我们分两部分,(?<=:)(\w*)
和 (\w*)(?=\.)
。这样就清楚了,正向肯定查找会匹配到 Jerry
仅仅当它后面跟着 .
,且不会把 .
当做匹配的内容。反向肯定查找会匹配到 Jerry
仅仅当它前面跟着:
,且不会把 :
当做匹配的内容。两个结合起来就是,正则表达式会匹配到任意字符串仅仅当它的前面跟着 :
,且仅仅当它后面跟着 .
注意:因为 .
在正则表达式里面代表除换行符之外的任何单个字符,所以需要转义才能匹配到 .
,即 \.