资讯专栏INFORMATION COLUMN

【实践】玩转正则表达式+JS正则处理函数

DoINsiSt / 2642人阅读

摘要:前言写这篇文章不是空穴来风,最近一个礼拜写了一个简单的脚本,用来处理上千个文件,以便于在某些特定字符的周围添加标记,先说一下我这个脚本使用场景主要是来识别中文具体做什么,之后会多带带写一篇文章,此处只提该脚本作用,同时为不同的文件类型,包括,

前言

写这篇文章不是空穴来风,最近一个礼拜写了一个简单的nodejs脚本,用来处理上千个文件,以便于在某些特定字符的周围添加标记,先说一下我这个脚本使用场景主要是来识别中文(具体做什么,之后会多带带写一篇文章,此处只提该脚本作用),同时为不同的文件类型,包括js,vm,jsp等等文件的中文周围添加标记,以便于减少人工添加标记的事件。

注:本文着重用示例讲解,理论知识推荐此篇文章 http://www.jb51.net/tools/zhe... 最早我就是看的这篇文章初步接触正则,正则刚开始很枯燥,慢慢学就好了,加油!!!

1. 正则理论部分简介

只是看下面的这些还是处于懵逼状态,其实直接看第二节例子即可,为了完整性此处便于大家查阅!

[] 集合

{} 范围

() 分组

| 并列关系

+ 一次或者多次(范围简写方式1)

* 零次或多次(范围简写方式2)

? 零次或一次(范围简写方式3) 另外和贪婪模式有关,后面会讲

^ 两个功能,放在开始作为开始符,放在[]的开头作为“非”

$ 结束符

转义

(?=pattern) 正向肯定环视(这个名字好多地方都不一样,断言,预查,我最喜欢环视,同下)

(?!pattern) 正向否定环视

(?<=pattern) 逆向肯定环视

(? 逆向否定环视

. 匹配除换行符之外的所有字符(此项以下为范围集)

s 匹配任何空白字符,包括空格、制表符、换页符等等。

S 匹配任何非空白字符(s的反面)

d 匹配数字字符

D 匹配非数字字符(d的反面)

w 匹配字母、数字、下划线

W 匹配非字母、数字、下划线

以上这些我觉得就是比较常用的基本能够够大家使用的了,对于中文站一般还会用到中文的相关匹配,那么中文的匹配为[u4e00-u9fa5],其中u是四个十六进制数字表示的Unicode字符,不知道匹配的中文是否全,但是大部分还都是可以的

2. 正则简单调试

实际上调试正则可以不需要什么工具,你要非得要的话,可以用Note Pad++,这个简单的编辑器内置有正则的匹配,Ctrl+F弹出对话框里边是含有正则选择项,打上对勾即可以在编辑其中写内容,看看能否搜索到了。

我建议看此篇文章或者练习的时候,在chrome浏览器直接Windows系统按F12, Mac上按command+option+J,点击console或者控制台,用什么浏览器自行研究如何打开控制台,如图

光标位置即可操作js,然后利用js的就可以展示你写的正则是否正确,很速度的方式,可以用上下键来切换,迅速修改你的表达式

3. JS相关处理函数

下文的Reg代表正则表达式,str代表要匹配的字符串,由于还未开始正则表达式讲解,如果有无法理解请略读,了解如何利用这几个函数,然后开始进行第四节正则学习,然后回头看就OK了。

RegExp方法

test

用法:Reg.test(str)
返回值:Boolean
实例:/a/.test("a") // true

exec

用法:Reg.exec(str)
返回值:Arraynull
实例1:/b(a)/.exec("ba") // ["ba", "a", index: 0, input: "ba"]
实例2:/a(c)/.exec("ba") // null
解释:匹配的值会按照顺序-->全匹配,第一分组,第二分组...等等,匹配到的字符串位置(index),输入的字符串(input)

String方法

match

用法:str.match(Reg)
返回值:Arraynull
其实和RegExptest方法是一致的,只不过这个字符串在前
注意:当区分模式时match返回情况有所区别
实例1:"bababa".match(/b(a)/g) // ["ba", "ba", "ba"]
实例2:"bababa".match(/b(a)/) // ["ba", "a", index: 0, input: "bababa"]

search
用法:str.search(Reg)
返回值:Number 位置索引(无匹配返回-1)
实例:"wefeaba".search(/b(a)/) // 5

split

用法:str.split(str)str.split(Reg) 【自动全局搜索】
返回值:Array 将分开的子字符串放到数组中
实例1:"前端,后端,设计".split(",") // ["前端", "后端", "设计"]
实例2:"f4wef1er2gr".split(/d/) // ["f", "wef", "er", "gr"]

replace

用法:str.replace(str, str)str.replace(Reg,str)str.replace(Reg,Fn)
实例1:"前端,后端,设计".replace(",", "|") // "前端|后端,设计"
实例2:"前端,后端,设计".replace(/,/, "|") // "前端|后端,设计"
实例3:"前端,后端,设计".replace(/,/g, "|") // "前端|后端|设计"
实例4:

"前端,后端,设计".replace(/,/g, function($all){
    return "{" + $all + "}";
});
// "前端{,}后端{,}设计"

实例5:

"1、这是例子balabala".replace(/1、([u4e00-u9fa5]+)[a-z]*/g, function($all, $1){
    return "{" + $1 + "}";
})
// "{这是例子}"

解释: replace的函数参数顺序为-->全匹配,第一捕获组,第二捕获组...

4. 由浅入深讲解正则

边练习边写,你会发现无穷的乐趣,看到中途累了休息一下

最简单的正则

/a/

用途:匹配a,只要串中包含a即可
说明:js中用两个/来圈定正则,中间的a即为要匹配的字符

实例:/a/.test("ab") // true

我们现在看一个使用场景,你提供了一个输入框,这个输入框是让用户输入手机号,先来个最简单的规则,用户的手机号应为11位数字,这是一个最简单的正则,如下所示。

/^d{11}$/

用途:匹配从开始到结尾共11位数字的字符串
说明:^用来标识开头,$用来标识结尾,d为数字集合,{11}代表将d循环11次
注意:用来判断某字符串正确与否一定要加开始结束标识符,看实例2即可看出端倪,十二位数字也被匹配上了,也就是只要串中包含正则可匹配的就能成功,此处可以看出开始结束符的重要性

实例1:/^d{11}$/.test("13212344321") // true
实例2:/d{11}/.test("132123443211") // true

/^d{5,11}$/

用途:匹配从开始到结尾共5-11数字均可的字符串
说明:{5,11} 集合来标识5到11位,可以{5,}来表示5到n多位

实例1:/^d{5,11}$/.test("1234") // false
实例2:/^d{5,11}$/.test("1234567") // true

下面继续拓展,组合上面方式

/^132d{8}$/

用途:匹配开头为132的手机号码
说明:132其实就是直接匹配这三个字符,后面的其实就是动态匹配8位数字,合起来就是11位了

实例1:/^132d{8}$/.test("18912344321") // false
实例2:/^132d{8}$/.test("13212344321") // true

手机号不是只有132开头的啊,如果我想用189开头的呢,请看

/^(132|189|133)d{8}$/

用途:匹配开头为132或189或133的手机号
说明:此处应该注意我们用到了分组()和并列关系|,并列就很简单了就是说可以132可以189可以133,此处一定注意分组是一定要用的如果不用就会出现实例1的情况,因为并列关系不是前面数字了,变成了三部分了

实例1:/^132|189|133d{8}$/.test("132") // true
实例2:/^(132|189|133)d{8}$/.test("132") // false
实例3:/^(132|189|133)d{8}$/.test("18912344321") // true
实例4:/^(132|189|133)d{8}$/.test("13212344321") // true

现在来看另一个场景,如果我们不是判断手机号,而是在一堆中文介绍中提取出手机号,那么需要怎么办呢?

匹配内容:"大家好,我叫jackwang,我的手机号是{13212344321},他的手机号为{13212344321}测试"

/{((132|189|133)d{8})}/

用途:用来匹配文中的手机号,注意手机两边有标识{}我们有这个定位符会很方便将其匹配出来
说明:首先,可以看到{,我们前面提到了{}为正则特殊字符,虽然此处不加也可以,但是好习惯就是特殊字符要加上避免出问题,例如{1},如果你要匹配的不是前面的东西循环一次那么就会出问题了;另外,看到我用两个()这相当于有两个捕获组,请看实例(这回我用exec,会看的更直接)

实例1:/{((132|189|133)d{8})}/.exec("大家好,我叫jackwang,我的手机号是{13212344321},他的手机号为{13212344321}测试")
// ["{13212344321}", "13212344321", "132", index: 21, input: "大家好,我叫jackwang,我的手机号是{13212344321},他的手机号为{13212344321}测试"]

可以看到第一捕获组放在了索引为1的位置,我们就可以直接取用了,不过我们会想如果串中如果有多个电话号想搞怎么办,就像上面这段字符串,下面我给出js写法,并解释

var str = "大家好,我叫jackwang,我的手机号是{13212344321},他的手机号为{13212344334}测试";
var reg = /{((132|189|133)d{8})}/g;

console.log(reg.exec(str));
console.log(reg.exec(str));

// ["{13212344321}", "13212344321", "132", index: 21, input: "大家好,我叫jackwang,我的手机号是{13212344321},他的手机号为{13212344334}测试"]

// ["{13212344334}", "13212344334", "132", index: 41, input: "大家好,我叫jackwang,我的手机号是{13212344321},他的手机号为{13212344334}测试"]

说明:g正则后面加个g表示全局模式;关于模式,i表示不区分大小写,m表示多行模式,我很少用,此处不讲了;对于exec有这么个特性,当正则表达式为全局匹配模式每次执行exec后会刷新下一次执行开始位置,下一次的开始位置为第一次匹配的最后一个字符的下一个位置,所以执行两次就会将串中所有的匹配出来,这样就实现了提取的目的

继续看上面的这段文本,如果我想匹配jackwang怎么办呢?

/[acgjknw]+/

用途:匹配包含acgjknw这些字符的1或多次循环
说明:[]是字符集,里边的就是要表示的字符,后面加一个+那么就是表示将前面的[]里边的循环1次或多次,同理?*不再用例子展示了

实例:/[acgjknw]+/g.exec("大家好,我叫jackwang,我的手机号是{13212344321},他的手机号为{13212344334}测试")
// ["jackwang", index: 6, input: "大家好,我叫jackwang,我的手机号是{13212344321},他的手机号为{13212344334}测试"]

可以看到我们写了很多字母,其实我们想匹配英文名,英文名不一定只有这几个字符,所以此处我们可以这样

/[a-z]+/

用途:匹配包含a-z的1或多次循环
说明:注意-这是范围的意思,按照ASCII中的顺序,写这个范围就行,这回我搞脚本的时候就遇到一个坑,如实例2,本来想匹配:-=,但是忘记对-进行转义,导致<也被匹配上

实例1:/[a-z]+/g.exec("大家好,我叫jackwang,我的手机号是{13212344321},他的手机号为{13212344334}测试")
// ["jackwang", index: 6, input: "大家好,我叫jackwang,我的手机号是{13212344321},他的手机号为{13212344334}测试"]
实例2:/[:-=]/.test("<")// true

还有一些什么没讲呢,下面多带带举例来说明

贪婪模式/非贪婪模式
字符串:"baeabaeab"

/b[a-z]+b//b[a-z]+?b/

说明:前者为贪婪模式,后者为非贪婪模式;请注意+后面的?添加了就为非贪婪模式,同理*和"?"后面可以添加;贪婪模式就是多次循环会尽可能的去匹配,非贪婪模式就是最少匹配,看实例结果即可明白,此正则功能很有用希望大家记住

实例1:/b[a-z]+b/.exec("baeabaeab")
// ["baeabaeab", index: 0, input: "baeabaeab"]
实例2:/b[a-z]+?b/.exec("baeabaeab")
// ["baeab", index: 0, input: "baeabaeab"]

反义

/[^5]/

说明:只要在集合的最开始用^即可,就是表示除了5之外所有字符

实例:/[^5]/.test("5") // false

环视

环视其实某些情况还是挺好用的,还记得前面的匹配手机号吗?

字符串: "大家好,我叫jackwang,我的手机号是{13212344321},他的手机号为13212344334测试"

其实我们还可以用环视

/(?<={)((132|189|133)d{8})(?=})/

实例:/(?<={)((132|189|133)d{8})(?=})/.exec("大家好,我叫jackwang,我的手机号是{13212344321},他的手机号为13212344334测试")
// ["13212344321", "13212344321", "132", index: 22, input: "大家好,我叫jackwang,我的手机号是{13212344321},他的手机号为13212344334测试"]

说明:刚开始环视可能比较难以理解,我通俗点讲,我觉得比我最开始提到的文章好理解

这就像站队一样,我在一排中想要找出你来,就可以直接匹配,但是我要找出张三和李四中间的你,但是我只想要你,不要带着他俩,那么环视就是这个功能

环视被包含的东西是不参与到正则最后匹配出来的东西当中的,它只起到一个定位的作用

(?<={)逆向肯定环视,举例来说,在匹配132之前要从1往回看,也就是逆向看看他的上一位是不是{,如果是的话才算合法,如果不是就匹配不成功,也就是你要往前看不是张三,那我就不找你了。同理,(?=})正向肯定环视,也就是匹配手机号之后,后面一定要有},这样才算成功,也就是你向后(顺序)看是李四才行,这整个表达式也就是你向前(逆向)看必须是张三,向后(正向)看必须是李四,我才会找你。

上面两个是肯定状态,另外还有两个否定状态,意思就是反的,(?逆向否定环视(?!pattern)正向否定环视, pattern为要匹配的表达式,举个例子

/(?

说明:匹配手机号前面没有{后面没有}的手机号

实例2:/(?
// ["13212344334", "13212344334", "132", index: 41, input: "大家好,我叫jackwang,我的手机号是{13212344321},他的手机号为13212344334测试"]

综上,看出来这两个实例的不同了吗,当然你可以任意匹配这四种方式来达到你要的效果;但是注意,可能每种语言支持程度不同,不要过度依赖。

5. 其他

匹配任意字符建议使用 /[sS]+/因为.会去掉换行符
注意用到的特殊字符一定要转义(好习惯) /[{}[]^$]/
注意-的使用 /[:-=]/ 这样会匹配<等,注意转义

运算符优先级

运算符 描述
转义
()[] 圆括号和方括号
*, +, ?, {n}, {n,}, {n,m} 限定符
^, $, 任何元字符、任何字符 定位点和序列
| 或操作

关于那些js的处理函数,自己去摸索吧,篇幅这么长,估计要看不下去了,我搞脚本的时候大量使用了replacetest函数,很好用,对于文件整体处理操作很好用,建议好好学学,请见MDN:https://developer.mozilla.org...

可能还有其他一些没讲到的正则知识,但是上面的这些基本包含了正则的90%了。

总结

啰里啰嗦讲了这么久,只是为了让新手能够由浅入深的慢慢学习,学习正则不是一蹴而就的过程,需要慢慢使用,慢慢探索,同一个匹配可能能写出好多正则,大家可以慢慢练习,写出更优雅的正则。

另外要说一点,不是非要写一个巨长的正则来匹配巨难的字符串,要合理利用各语言的函数来简化正则的写法,否则一个巨长的正则可能就是噩梦,这个事自己权衡,相信会将正则用到极致。

谢谢!

本文如有疏漏之处或者又问题交流,请直接回复本文!

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/90013.html

相关文章

  • 玩转javascript RegExp对象

    摘要:玩转对象中的正则表达式的正则表达式语法极大地借鉴了另一种脚本语言的正则表达式语法对象是的一个内置对象,与,类似。创建对象可通过构造函数创建。当要根据用户输入来构造正则表达式时,必须采用构造函数方式。如与被看做相同的字符模式。 玩转javascript RegExp对象 js中的正则表达式 js的正则表达式语法极大地借鉴了另一种脚本语言Perl的正则表达式语法.RegExp对象是js的一...

    alexnevsky 评论0 收藏0
  • 正则达式

    摘要:本文内容共正则表达式火拼系列正则表达式回溯法原理学习正则表达式,是需要懂点儿匹配原理的。正则表达式迷你书问世了让帮你生成和解析参数字符串最全正则表达式总结验证号手机号中文邮编身份证地址等是正则表达式的缩写,作用是对字符串执行模式匹配。 JS 的正则表达式 正则表达式 一种几乎可以在所有的程序设计语言里和所有的计算机平台上使用的文字处理工具。它可以用来查找特定的信息(搜索),也可以用来查...

    bang590 评论0 收藏0
  • 【前端早读会】每天记录前端学习的过程

    摘要:在这里使用学而思网校的录像设备,记录前端工程师每天学习的内容商城小程序分享人王聪视频插件开发分享人魏媛视频原理分享人李佳晓视频讲座优化实战分享人江芊视频文件操作分享人张凯视频一次性学会正则表达式分享人贺杰视频浅谈 在这里使用学而思网校的录像设备,记录前端工程师每天学习的内容: 2019-8-22 商城小程序codereview 分享人:王聪 视频:https://lecture.xue...

    tylin 评论0 收藏0
  • 一篇文章带你玩转正则达式

    摘要:读这篇文章之前你需要掌握基本的知识,并且有安静舒适的环境与宽裕的时间,文章有点长,你可以选择备好或茶来慢慢学习。文章标题有点夸大了,这是一篇正则表达式的入门文章。如有错误,欢迎指正。 读这篇文章之前你需要掌握基本的JavaScript知识,并且有安静舒适的环境与宽裕的时间,文章有点长,你可以选择备好coffee或茶来慢慢学习。文章标题有点夸大了,这是一篇正则表达式的入门文章。如有错误,...

    ermaoL 评论0 收藏0
  • 即将立秋的《课多周刊》(第2期)

    摘要:即将立秋的课多周刊第期我们的微信公众号,更多精彩内容皆在微信公众号,欢迎关注。若有帮助,请把课多周刊推荐给你的朋友,你的支持是我们最大的动力。课多周刊机器人运营中心是如何玩转起来的分享课多周刊是如何运营并坚持下来的。 即将立秋的《课多周刊》(第2期) 我们的微信公众号:fed-talk,更多精彩内容皆在微信公众号,欢迎关注。 若有帮助,请把 课多周刊 推荐给你的朋友,你的支持是我们最大...

    ruicbAndroid 评论0 收藏0

发表评论

0条评论

DoINsiSt

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<