三十分钟包会——正则表达式
一、前言
正则表达式,对大家来说既熟悉又陌生。熟悉是因为工作中有很多场景能用到,比如手机号、邮箱、密码等规则校验。
陌生则是因为正则表达式看上去就是一堆乱码,且一眼看上去很难看懂匹配规则。有时候在网上去找一个特定规则的正则表达式,搜出来的结果各不相同,执行效果更是不尽人意,想自己去修改,感觉也无从下手。
今天就花费30分钟时间,带领大家从另一个角度去剖析匹配的目的,理解匹配的思路,一步一步抽丝剥茧去学会怎么写正则表达式(读正则表达式远比写正则表达式要困难的多)。
二、理解正则要干的事情
正则要干的事情,可以总结为以下灵魂三问:
Q1、匹配啥?
Q2、匹配不是啥?
Q3、匹配多少次?
Q1、匹配啥?
这个比较好理解,比如想匹配字符a,那就直接写/a/
,只要字符串某个位置是a就可以匹配上:
/a/.test("javascript") //true
复制代码
匹配以a开头的字符串,就加上元字符^
(开始位置标识),/^a/
:
/^a/.test("javascript") //不是以a开头返回false
/^a/.test("abc") //是以a开头返回true
复制代码
匹配以a结尾的字符串,就加上元字符$
(结束位置标识),/a$/
:
/a$/.test("javascript") //不是以a结尾返回false
/a$/.test("cba") //是以a结尾返回true
复制代码
匹配字符a或b,可以把对应的字符放入中括号里/[ab]/
,只要字符串包含a或者b就可以匹配上:
/[ab]/.test("byte") //true
复制代码
匹配字符串abc或xyz,/abc|xyz/
:
/abc|xyz/.test("aabbxyz") //本字符串包含xyz,所以返回true
复制代码
① 匹配啥前面的(前瞻)
exp1(?=exp2)
:匹配exp2前面的exp1,匹配结果不包含exp2
比如要匹配字符串中script前面的部分java, /java(?=script)/
:
/java(?=script)/.test("javascript,javaee,typescript") //字符串中javascript符合规则 会返回ture//1、用exec方法来验证下匹配的结果
/java(?=script)/.exec("javascript,javaee,typescript")
//2、得到匹配结果如下:
["java", index: 0, input: "javascript,javaee,typescript", groups: undefined]
//3、会发现匹配到的是java,index是0,说明找到了的是javascript中script前面的java
复制代码
② 匹配啥后面的(后顾)
(?<=exp2)exp1
:匹配exp2后面的exp1,匹配结果不包含exp2
比如要匹配字符串中java后面的ee, /(?<=java)ee/
:
/(?<=java)ee/.test("javascript,javaee,typescript") //字符串中javaee符合规则 会返回ture//1、用exec方法来验证下匹配的结果
/(?<=java)ee/.exec("javascript,javaee,typescript")
//2、得到匹配结果如下:
["ee", index: 15, input: "javascript,javaee,typescript", groups: undefined]
//3、会发现匹配到的是ee,index是15,说明找到了的是javaee中java后面的ee
复制代码
Q2、匹配不是啥?
匹配不是啥,意思就是取反,只要不是这些的都可以匹配,比如不想匹配字符a,正则写法为/[^a]/
,是在中括号里面加上元字符^
,这样只要字符串满足有不是这个集合里面的字符,都可以被匹配上:
/[^a]/.test("aaa") //字符串全是a,返回false
/[^a]/.test("abc") //字符串不全是a,返回true
复制代码
匹配不是以a开头的,跟之前匹配啥类似,加上元字符^
,/^[^a]/
:
/^[^a]/.test("javascript") //此字符串不是以a开头,返回true
/^[^a]/.test("abc") //此字符串是以a开头,返回false
复制代码
匹配不是以a结束的,也跟之前匹配啥类似,加上元字符$
,/[^a]$/
:
/[^a]$/.test("javascript") //此字符串不是以a结束,返回true
/[^a]$/.test("cba") //此字符串是以a结束,返回false
复制代码
不匹配字符a、b、c,可以把对应的字符都放入中括号里/[^abc]/
:
/[^abc]$/.test("abccba") //此字符串的字符全部都不符合,返回false
复制代码
① 匹配后面不是啥的(负前瞻)
exp1(?!exp2)
:匹配后面不是exp2的exp1,匹配结果不包含exp2
比如要匹配字符串中后面不是script的java, /java(?!script)/
:
/java(?!script)/.test("javascript,javaee,typescript") //字符串javaee符合规则 会返回ture//1、用exec方法来验证下匹配的结果
/java(?!script)/.exec("javascript,javaee,typescript")
//2、得到匹配结果如下:
["java", index: 11, input: "javascript,javaee,typescript", groups: undefined]
//3、会发现匹配到的是java,index是11,说明找到了的是javaee中的java,因为这个java后面是ee
复制代码
② 匹配前面不是啥的(负后顾)
(?<!exp2)exp1
:匹配前面不是exp2的exp1,匹配结果不包含exp2
比如要匹配字符串中前面不是java的script,/(?<!java)script/
:
/(?<!java)script/.test("javascript,javaee,typescript") //字符串中typescript符合规则 会返回ture//1、用exec方法来验证下匹配的结果
/(?<!java)script/.exec("javascript,javaee,typescript")
//2、得到匹配结果如下:
["script", index: 22, input: "javascript,javaee,typescript", groups: undefined]
//3、会发现匹配到的是script,index是22,说明找到了的是typescript中type后面的script
复制代码
③ 不匹配包含abc的字符串
这是一个比较特殊的匹配行为,如果只是写成/[^abc]/
的话,这只意味着字符串不能全是由a、b、c这三个组成的,跟需求不匹配。
那我们要从另外一个角度去分析,字符串的任意一个位置开始都不能连续出现abc,我们可以利用负前瞻的特性来匹配,然后一步一步来实现这个正则:
- 位置后面不能是abc,使用负前瞻匹配位置:
/(?!abc)/
- 从开始到结束每个位置都要覆盖到,添加开始结束标记:
/^(?!abc)/$
- 这个位置后面可以是其他的字符,用
\w
来表示:/^(?!abc)\w$/
- 满足上面情况后的位置,可以连续出现多个,用
+
来表示数量:/^((?!abc)\w)+$/
/^((?!abc)\w)+$/.test("cbacbac") //本字符串中不包含连续的abc,结果返回true
/^((?!abc)\w)+$/.test("cbacbabc") //本字符串中包含连续的abc,结果返回false
复制代码
Q3、匹配多少次?
匹配一次可以什么都不用定义,比如匹配一个数字/\d/
,如果要匹配连续三个数字最简单的方式就是连续写三次:/\d\d\d/
,这样写本身是没有问题的,能正确匹配。
但是如果次数太多或者次数不确定,这么写肯定不行,所以可以加上长度规则:
*
:匹配任意次
+
:最低匹配1次
?
:匹配1次或者0次
{m}
:匹配m次
{m,}
:最低匹配m次
{m,n}
:最低匹配m次,最多匹配n次,m需要小于等于n
正则默认是贪婪匹配,就是符合条件的会一直匹配,如果想阻止贪婪匹配,可以在长度规则后面加一个?
,比如:
/\d{2,}/.exec("1234567890")
//得到匹配结果如下,会匹配到所有数字:
["1234567890", index: 0, input: "1234567890", groups: undefined]//1、添加?,阻止非贪婪匹配后
/\d{2,}?/.exec("1234567890")
//2、得到匹配结果如下,只会匹配2个数字:
["12", index: 0, input: "1234567890", groups: undefined]
复制代码
① 使用分组
如果想匹配多次某个单词如regregregregregreg时候怎么办,我们看到reg连续出现了6次,如果傻傻的把6个reg写在了正则表达式中肯定不合适,我们就可以利用分组来实现,我们把reg放在括号里面,然后让这个分组重复6次,/(reg){6}/
:
/(reg){6}/.test("regregregregregreg") //匹配成功,返回true
复制代码
不过这样利用分组是有个前提,就是知道要匹配的字符串就是reg,然后重复这个分组。如果想匹配类似8899或者5522这种重叠类型的字符怎么办呢?那我们可以把重叠的第一个放入分组,再通过\n
捕获这个分组内容来匹配下一个:
/(\d)\1(\d)\2/.exec("2345566789")
//得到匹配结果如下,返回了5566,分组对应的5、6也被返回
["5566", "5", "6", index: 3, input: "2345566789", groups: undefined]
复制代码
② 分组捕获
默认的分组是可以被捕获的,上面的\1
、\2
是在正则表达式内部捕获的分组。如果想在外部去捕获分组匹配的数据可以使用RegExp.$1-$9
来获取。只要正则匹配了就会有。可以使用test
、exec
或者str的replace
方法来获取$1-$9
。
使用test:
/([a-z]{2})(\d{2})/.test("xyz123")
RegExp.$1 //返回第一个分组表达式匹配到的内容 yz
RegExp.$2 //返回第二个分组表达式匹配到的内容 12
复制代码
使用replace:
"xyz123".replace(/([a-z]{2})(\d{2})/,'$2$1')
//会返回结果:x12yz3,就是把第一个分组匹配到的内容yz和第二个分组匹配到的内容12互换了
复制代码
③ 分组不捕获
如果不想捕获分组,只需要在分组内加上?:
就可以了
/([a-z]{2})(?:\d{2})/.test("xyz123")
RegExp.$1 //返回第一个分组表达式匹配到的内容 yz
RegExp.$2 //分组未被捕获 返回空字符串
复制代码
三、总结
本文不去赘述元字符的含义以及组合使用方法,这些是需要记死背硬的东西。而是教给大家一种如何切入正则表达式的思维,怎么去一步步分析要匹配的需求,把长的、复杂的需求拆成短的、简单的,正向不行的就逆向去分析,一点一点去组合,然后回归灵魂三问:匹配啥?匹配不是啥?匹配多少次? ,去完成符合要求的正则表达式。
本文首发于前端黑洞网,csdn同步跟新
三十分钟包会——正则表达式相关推荐
- 大饼博士X Blog文章索引:机器学习方法系列,深度学习方法系列,三十分钟理解系列等
(我怕忘了这好资源) 欢迎转载,转载请注明:本文出自Bin的专栏blog.csdn.net/xbinworld. 技术交流QQ群:433250724,欢迎对算法.机器学习技术感兴趣的同学加入. 以下是 ...
- 我的Blog文章索引::机器学习方法系列,深度学习方法系列,三十分钟理解系列等
欢迎转载,转载请注明:本文出自Bin的专栏blog.csdn.net/xbinworld. 技术交流QQ群:433250724,欢迎对算法.机器学习技术感兴趣的同学加入.纯技术交流. 以下是我利用业余 ...
- 三十分钟完成一个“我们是谁”编辑器 - 20170819前端开发日报
记得点击文章末尾的"阅读原文"查看哟~ 下面先一起看下今天的日报摘要吧~ 三十分钟完成一个"我们是谁"编辑器 这两天朋友圈又被刷屏了,这次是"我们是谁 ...
- 今天三十分钟会议看时间管理
今天开了三十分钟的会议有关于时间管理,疫情封闭的一个月时间以来,缺卡次数增加,自己在家对于时间管理方面有了一些懈怠,为了能更好的做好时间管理,首先要从打卡坐起. 利用好自己手里的智能工具,如闹铃,循环 ...
- BootStrap三十分钟入门
OK,距离上次发博客居然已经有三个月了,上次写的Ext也没有写完,很对不起大家,事情总是来不完的,弄着弄着就忘记了自己还有博客这回事了. 这次我们说个html框架:BootStrap,来自Twitte ...
- 08-18 三十分钟的反弹
以下复盘仅为个人对市场的思考历程,总结回顾!绝非荐股.带单,请勿跟随. 2021年08月18日 一.行情走势回顾: 1.大盘行情 截至收盘,上证指数涨1.11%,报3485.29点,深证成指涨0.72 ...
- EditText 禁止输入表情包的正则表达式
EditText 禁止输入表情包的正则表达式 InputFilter emojiFilter = new InputFilter() {Pattern emoji = Pattern.compile( ...
- 三十分钟在Windows10安装Anaconda+Pytorch+Cuda,老式Nvidia GTX游戏显卡实测可用
文章目录 1. 安装Anaconda 3.5 2. 用conda安装Pytorch及相关依赖软件 3. 简单测试安装环境(pytorch/cuda/cudnn) 5. 给conda环境用pip安装gy ...
- 微直播笔记|三十分钟微信小游戏开发入门
微信小游戏在2017年12月28日正式上线.相对于传统的H5游戏,小游戏的优势十分明显,拥有微信庞大的用户量以及更好的兼容性,在天生适合微信社交生态的同时还不用担心被屏蔽.无疑,这或许是一个巨大的风口 ...
最新文章
- Zzz读书心得:英文论文写作不求人
- 线程中start()与run()的区别
- 初始化栈的代码_数据结构中的栈,你知道多少?
- 谷歌开发者大会焦点:大中华区新掌门亮相,Android 10原生支持5G,TF2.0大更新...
- 160-PHP 文本替换函数str_replace(一)
- 人人都能读懂的编译器原理
- apple quicktime怎么在ppt中用_PPT情感专题大赏No. 007:一份这就是街舞第三季主题PPT(上集)...
- Mblog 开源Java多人博客系统
- 蚂蚁森林用户须知_蚂蚁森林刷能量漏洞(轻松读懂规则)
- 手机上怎么安装Java的软件游戏
- 360浏览器通过访问插件管理界面启用flash实例演示,360浏览器启用Adobe Flash Player方法
- 2021-07-23
- [android issue解析] fd leakage cause app ANR
- 梳理审批流程的程序编码流程
- 一、Docker 容器
- 语句摘抄——第26周
- 【附源码】Java计算机毕业设计安卓高速铁路配餐app论文(程序+LW+部署)
- 伤害世界怎么自建服务器,《伤害世界Hurtworld》服务器架设方法图文详解 怎么开服?...
- 【转】最优传输理论---(微信公总号:老顾谈几何)顾险峰
- 雨听 | 英语学习笔记(六)~作文范文:公务员考试的热潮
热门文章
- 利用Pin实现CodeCoverage
- SkyEye仿真平台下的操作系统实验- 准备篇(一)
- MySQL深度剖析之数据在磁盘上存储(2021)
- (48)Xilinx Adder IP核配置(九)(第10天)
- (20)Zynq FPGA Quad-SPI闪存控制器介绍
- python连接不上数据库_绕不过去的Python连接MySQL数据库
- 7006.vue项目之电商项目实战1-环境搭建及后台接口测试
- STM32中断与事件
- java file list listfiles,Java File listFiles()用法及代码示例
- 高性能HTTP加速器Varnish(性能调优篇)