最近发现很多的面试和笔试中都经常出现正则表达式相关的题目,面试官:这么简单的正则表达式都不会?面试者:嘴角微微上扬,回以一个不失礼而尴尬的笑
熟练掌握正则表达式,不仅能够在面试中体现编程水平,在平时的开发过程中也能够用于优化我们的代码,让我们写出更加精炼的语句,
这不就是老鸟装ABCDEFG之道吗,
在CodeReview的时候假装不经意间写出一条老长老长的正则表达式,丢到新鸟面前,云淡风轻得说一句,这不就简简单单一条正则就能解决吗,写这么多代码干嘛?
回到正题,最近这段时间重新学了下正则表达式,还是发现正则表达式有很多值得学习的地方,今天我就通过这篇文章记录一下自己学习正则表达式的笔记,也希望能够分享给大家,一起快乐搬砖!
先来举个例子,题目是这样子
给出两个字符串 str 和 sub,你的任务是在 str 中完全删除那些在 sub 中存在的字符。
注:字符串包含空格,1≤len(str),len(sub)≤10^5
输入:
str="I am YimWu",sub="abc"
输出:
"I m YimWu"
我们来看一下,作为不知道正则表达式的小白,我们该怎么处理呢?万物皆可循环,这个时候我们祭出祖传“循环+判断”王炸组合
let CharacterDeletion = (str, sub) => {
// 剔除字符串中所有的目标字符
let replaceFun = (replaceStr,char) => {
// 用于保存剔除操作后的字符串
let r = replaceStr
// 若没有找到对应字符则返回原字符串
if(r.indexOf(char) == -1){
return r
}else{
// replace匹配到第一个字符并剔除
r = r.replace(char,'')
// 剔除后再次检查是否还有需要剔除的字符
// 无则返回,有则递归调用原函数
if(r.indexOf(char) == -1){
return r
}else{
return replaceFun(r, char)
}
}
}
let r = str
sub.split('').forEach(ele => {
r = replaceFun(r, ele)
});
return r
}
// 输出返回
console.log(
CharacterDeletion('I am YimWu', 'aeiou') // result => I m YmW
)
到这里总算憋屈地把结果写出来了,虽然代码量不算很多,但是由于 node 环境中不支持replaceAll (Version>85的chrome支持),所以只能用递归来完成replaceAll的功能,所以代码的可读性随即降低了很多,这里可能还有其他的解法,就不一一展示了,有兴趣的小伙伴可以留言区交流交流
说完了上面憋屈的解法,我们来看看使用正则表达式的写法
// 字符串过滤
let CharacterDeletion = (str, sub) => {
// 利用eval动态拼接正则表达式
let reg = eval(`/[${sub}]/g`)
return str.replace(reg, '')
}
// 输出返回
console.log(
CharacterDeletion('I am YimWu', 'aeiou') // result => I m YmW
)
OhMyGod!!!快,块扶我起来,我想学习!!
显而易见,对于第一种方法需要十几二十行代码才能解决的问题,利用正则表达式5行就可以直接解决,不仅代码量大大减少了,而且代码的可读性也提高了不少,所以还不快来跟我学一学这欲罢不能的正则表达式
正则表达式的用法有很多,但是平常我们工作中,面试中用到的大部分都是正则表达式的基础用法,所以今天主要以介绍基础的用法为主,如果需要更加系统,深入的学习正则表达式,可以阅读文末参考书籍、文章进行学习
按生活经验来说,我们都知道,如何事情,都有相对的两面,那么,正则表达式其实也一样,正则表达式也有两种相反的匹配方式,举两个实际应用的例子:
我们在用 webpack 打包时需要让 webpack 知道,什么文件用什么 loader 进行解析,那么我们需要在 webpack 的 module.rules 中写入匹配的正则表达式,匹配特定的文件后缀名,如 /\.vue/,这个表达式的作用是,匹配所有以 .vue 结尾的文件,这就是正向匹配
我们都知道前端安全问题主要集中在登录框、留言框以及各种接受输入的位置,那么作为前端,我们该如何防范呢,其中有一个比较有效的便是正则表达式的反向匹配。
前端最常见的攻击有两种,一种是xss攻击,另一种是注入攻击,两种攻击最基础的防范方式就是利用正则表达式,排除特殊字符(如<>|等),达到屏蔽部分攻击的可能
例如:
/[^%--`~!@#$^&*()=|{}':;',\[\]\.<>]/
这就是摘抄了某系统的过滤语句(不一定严谨),该语句匹配不符合的,才是前端允许输入的内容
const str = 'abc'
// test 验证是否满足正则表达式,返回 true/false
str.test(/[a-z]/)
// match 返回正则表达式匹配结果 返回数组
str.match(/[a-z]/)
字符 | 含义 |
---|---|
\d | [0-9]/表示0-9其中一位 |
\D | [^0-9]/表示除了0-9之外的任意字符 |
\w | [0-9a-zA-Z_]/表示数字、字母以及下划线 |
\W | [^0-9a-zA-Z_]/表示非单词、字母以及下划线 |
\s | [\t\v\n\r\f]/表示各种空白符号,空格、制表符等 |
\S | [^\t\v\n\r\f]/表示非空白字符 |
. | [^\n\r\u2028\u2029]/表示除了换行符、回车符、行分隔符和段分隔符之外的字符 |
字符 | 含义 |
---|---|
+ | {1, }/表示至少需要出现一次 |
* | {0, }/表示出现任何次,包含不出现 |
? | {0,1}/表示不出现或者出现一次 |
{m, } | 至少出现 m 次 |
字符 | 含义 |
---|---|
| | 表示分支,/a | b/, 表示a或b |
^ | 在开头表示匹配以某字符开头,在字符集中表示反向匹配 |
$ | 在末尾表示匹配以某字符结尾 |
| | 表示分支,/a | b/, 表示a或b |
/RegExp/ i | i 即 ignore,表示匹配时忽略大小写 |
/RegExp/ g | g 即 global,表示全文匹配 |
上面列了几个表格,把基本用法都罗列了一遍,理论已经到位,那么接下来就举一些我平时工作中具体的例子,看看如何利用这些字符,通过排列组合,实现灵活多变的需求吧!
// \d 表示匹配数字,{11}表示匹配11位
const str = 'yimwu: 19448751214'
str.match(/\d{11}/)
// \. 表示转义,vue$ 表示以 vue 结尾,即 vue 相关的源文件
const fileName = 'app.vue'
const reg = /\.vue$/
reg.test(filename)
const reg = /(\.png$)|(\.jpg$)/
const uploadFileName = 'pic.png'
reg.test(uploadFileName)
// 颜色由 #开头,加上3、6位16进制数组成
const reg = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/
reg.test('#c8c8c8') // true
// {4}量词前表示匹配年份
// (0[1-9]|1[0-2]) 匹配的是月份 01-12
// (0[1-9]|[12][0-9]|3[01]) 这里需要特别注意的是需要分情况匹配,若开头为3,则只有30/31满足匹配
const reg = /^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$/
reg.test("2022-03-22")
这篇文章算是一个正则表达式非常基础的入门篇吧,所涉及的正则表达式的内容也非常有限,只是以我平时的实际例子作为引子,希望能够给想了解正则表达式的朋友们做个简单的浏览,如果想更进一步系统的学习正则表达式,请阅读以下参考文章,各位前辈大佬们已经总结得很精辟了,大家可以移步拜读拜读!
该专栏将持续更新前端相关技术的整理与总结,欢迎订阅!
如果喜欢博主的文章,那就狠狠给博主点个赞呗,让我们一起成长吧!
欢迎关注博主文章首发号 掘金社区,转发记得私信博主哟哟!