写这篇文章不是空穴来风,最近一个礼拜写了一个简单的nodejs脚本,用来处理上千个文件,以便于在某些特定字符的周围添加标记,先说一下我这个脚本使用场景主要是来识别中文(具体作什么,以后会单独写一篇文章,此处只提该脚本做用),同时为不一样的文件类型,包括js,vm,jsp等等文件的中文周围添加标记,以便于减小人工添加标记的事件。html
注:本文着重用示例讲解,理论知识推荐此篇文章 http://www.jb51.net/tools/zhe... 最先我就是看的这篇文章初步接触正则,正则刚开始很枯燥,慢慢学就行了,加油!!!前端
只是看下面的这些仍是处于懵逼状态,其实直接看第二节例子便可,为了完整性此处便于你们查阅!node
[]
集合{}
范围()
分组|
并列关系+
一次或者屡次(范围简写方式1)*
零次或屡次(范围简写方式2)?
零次或一次(范围简写方式3) 另外和贪婪模式有关,后面会讲^
两个功能,放在开始做为开始符,放在[]
的开头做为“非”$
结束符\
转义(?=pattern)
正向确定环视(这个名字好多地方都不同,断言,预查,我最喜欢环视,同下)(?!pattern)
正向否认环视(?<=pattern)
逆向确定环视(?<!pattern)
逆向否认环视.
匹配除换行符以外的全部字符(此项如下为范围集)\s
匹配任何空白字符,包括空格、制表符、换页符等等。\S
匹配任何非空白字符(s的反面)\d
匹配数字字符\D
匹配非数字字符(d的反面)\w
匹配字母、数字、下划线\W
匹配非字母、数字、下划线以上这些我以为就是比较经常使用的基本可以够你们使用的了,对于中文站通常还会用到中文的相关匹配,那么中文的匹配为[\u4e00-\u9fa5]
,其中\u
是四个十六进制数字表示的Unicode字符,不知道匹配的中文是否全,可是大部分还都是能够的正则表达式
实际上调试正则能够不须要什么工具,你要非得要的话,能够用Note Pad++
,这个简单的编辑器内置有正则的匹配,Ctrl+F
弹出对话框里边是含有正则选择项,打上对勾便可以在编辑其中写内容,看看可否搜索到了。chrome
我建议看此篇文章或者练习的时候,在chrome
浏览器直接Windows
系统按F12
, Mac
上按command+option+J
,点击console
或者控制台
,用什么浏览器自行研究如何打开控制台,如图后端
光标位置便可操做js,而后利用js的就能够展现你写的正则是否正确,很速度的方式,能够用上下键来切换,迅速修改你的表达式数组
下文的Reg
表明正则表达式,str
表明要匹配的字符串,因为还未开始正则表达式讲解,若是有没法理解请略读,了解如何利用这几个函数,而后开始进行第四节正则学习,而后回头看就OK了。浏览器
testjsp
用法:Reg.test(str)
返回值:Boolean
实例:/a/.test("a")
// true编辑器
exec
用法:Reg.exec(str)
返回值:Array
或null
实例1:/b(a)/.exec("ba")
// ["ba", "a", index: 0, input: "ba"]
实例2:/a(c)/.exec("ba")
// null
解释:匹配的值会按照顺序-->全匹配,第一分组,第二分组...等等,匹配到的字符串位置(index),输入的字符串(input)
match
用法:str.match(Reg)
返回值:Array
或null
其实和RegExp
的test
方法是一致的,只不过这个字符串在前
注意:当区分模式时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:
"一、这是例子balabala".replace(/一、([\u4e00-\u9fa5]+)[a-z]*/g, function($all, $1){ return '{' + $1 + '}'; }) // "{这是例子}"
解释: replace的函数参数顺序为-->全匹配,第一捕获组,第二捕获组...
边练习边写,你会发现无穷的乐趣,看到中途累了休息一下
最简单的正则
/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
下面继续拓展,组合上面方式
/^132\d{8}$/
用途:匹配开头为132的手机号码
说明:132
其实就是直接匹配这三个字符,后面的其实就是动态匹配8位数字,合起来就是11位了
实例1:/^132\d{8}$/.test("18912344321")
// false
实例2:/^132\d{8}$/.test("13212344321")
// true
手机号不是只有132开头的啊,若是我想用189开头的呢,请看
/^(132|189|133)\d{8}$/
用途:匹配开头为132或189或133的手机号
说明:此处应该注意咱们用到了分组()
和并列关系|
,并列就很简单了就是说能够132能够189能够133,此处必定注意分组是必定要用的若是不用就会出现实例1的状况,由于并列关系不是前面数字了,变成了三部分了
实例1:/^132|189|133\d{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)
正向否认环视, pattern为要匹配的表达式,举个例子/(?<!\{)((132|189|133)\d{8})(?!\})/
说明:匹配手机号前面没有{
后面没有}
的手机号
实例2:/(?<!\{)((132|189|133)\d{8})(?!\})/.exec("你们好,我叫jackwang,个人手机号是{13212344321},他的手机号为13212344334测试")
// ["13212344334", "13212344334", "132", index: 41, input: "你们好,我叫jackwang,个人手机号是{13212344321},他的手机号为13212344334测试"]
综上,看出来这两个实例的不一样了吗,固然你能够任意匹配这四种方式来达到你要的效果;可是注意,可能每种语言支持程度不一样,不要过分依赖。
匹配任意字符建议使用 /[\s\S]+/
由于.
会去掉换行符
注意用到的特殊字符必定要转义(好习惯) /[\{\}\[\]\^\$]/
注意-
的使用 /[:-=]/
这样会匹配<
等,注意转义
运算符优先级
运算符 | 描述 |
---|---|
\ | 转义 |
()[] | 圆括号和方括号 |
*, +, ?, {n}, {n,}, {n,m} | 限定符 |
^, $, 任何元字符、任何字符 | 定位点和序列 |
| | 或操做 |
关于那些js的处理函数,本身去摸索吧,篇幅这么长,估计要看不下去了,我搞脚本的时候大量使用了replace
和test
函数,很好用,对于文件总体处理操做很好用,建议好好学学,请见MDN:https://developer.mozilla.org...
可能还有其余一些没讲到的正则知识,可是上面的这些基本包含了正则的90%了。
啰里啰嗦讲了这么久,只是为了让新手可以由浅入深的慢慢学习,学习正则不是一蹴而就的过程,须要慢慢使用,慢慢探索,同一个匹配可能能写出好多正则,你们能够慢慢练习,写出更优雅的正则。
另外要说一点,不是非要写一个巨长的正则来匹配巨难的字符串,要合理利用各语言的函数来简化正则的写法,不然一个巨长的正则可能就是噩梦,这个事本身权衡,相信会将正则用到极致。
谢谢!
本文若有疏漏之处或者又问题交流,请直接回复本文!