之前看了许许多多的正则教程,收货并很少,每每都是走马观花,一点就过。事实上,正则用处真的超级大,好比匹配innerHTML的内容,以及表单验证,也是非他莫属。这里,我结合js,对正则进行一个简单的介绍吧。 若有纰漏欢迎指出,但愿你们多多包涵。html
在js中定义一个正则有两种方法,一个是实例化,一个是字面量。
分别看一下:数组
//字面量 var re = /\w+/; //这二者等价 //实例化 var re = new RegExp('\\w+');
若是想添加一些flags也是没有问题的。
比较经常使用的flag有。/i,/g,/ig,/m.markdown
/i (忽略大小写,ignore) /g (全文查找出现的全部匹配字符,global) /m (多行查找,multiLine) /ig(全文查找、忽略大小写,ignore+global)
因此, 使用flag以后能够这样写.app
var reg = ^\d{5,12}\i$ ;//表示忽略大小写,匹配; //或者 var reg = new RegExp(^\d{5,12}\i$);
正则其实就是用来匹配字符串的。他用一个简洁表达了,完成了你须要写不少代码的事,就和md(markdown)语法是一个道理。 用的人多了,天然成标准,这也是规则吧。ide
预约字符,就是用程序比较难表达的一些字符,好比回车键,tab键(经过空格来区分达到的效果).
经常使用的有:工具
字符 | 效果 |
---|---|
t | 制表符,其实就是一个“Tab”键 |
r | 回车符,若是你使用过word应该以后,在一个段落后面那个东西吧。 :) |
n | 换行符,他和r是有故事的,等下说,咱们继续 |
恩,大部分就是这几个了。 上面提到 r和n,他们到底有什么却别。 没错,看字面量,感受return 不就是换行吗? 其实,这样说没错,可是得区分系统,在Unix为扩展的系统,在每行的结尾只有"n",而在window下则是:"rn"(顺序不能换). 因此,为了解决系统的差别,就出现了两种: r || n.
因此通常,咱们匹配换行须要使用.r||n一块儿使用.学习
var reg = /[\r\n]/g;
这样就能保证系统的兼容性.测试
所谓的字符类一样也是将你日常要花不少时间作出来的,集成为一个简洁表达。(至关于写库)。
经常使用的字符类有以下几个。fetch
字符 | 效果 |
---|---|
. | 匹配换行符之外的任意字符 |
d | 匹配全部数字 |
D | 匹配非数字 |
s | 匹配一个空格符 |
S | 匹配非空格 |
w | 匹配字母数字下划线=>其实就是匹配单词word(简单易懂) |
W | 匹配!字母数字下划线=>就是不匹配单词 |
来咱们看几个例子idea
console.log(/\s+/.test(" ")); //true console.log(/\d+/.test("1234231")); //true console.log(/\D+/.test(" ")); //true
其余的如上。
这个应该算是正则里面,取名最好理解的一个。使用正则就是停船同样,你须要设置你停的位置,我也须要设置个人边界。
经常使用的有一下几个:
锚字符 | 效果 |
---|---|
^ | 匹配字符串的开头,在多行检索中,匹配一行的开头 |
$ | 匹配字符串的结尾,在多行检索中,匹配一行的结尾 |
b | 匹配一个单词的边界 |
B | 匹配非单词边界 |
这几个应该算是我日常用的最多的几个吧。
若是你想匹配整个字符串,就能够组合使用"^ $";
var reg = /^\d+$/; //匹配整个字符串为数字
"望文生义",这类字符使用来限定某某出现的次数的。
经常使用的有:
代码 / 语法 | 说明 |
---|---|
* | 重复零次或更屡次 |
+ | 重复一次或更屡次 |
? | 重复零次或一次 |
{n} | 重复n次 |
{n,} | 重复n次或更屡次 |
{n, m} | 重复n到m次 |
这个应该不用多说了。 直接看例子吧
console.log(/^\d+$/.test("123")); //true
上面说了这么多内置的字符,那我想使用特定字符类怎么办嘞。其实也很简单。使用""转义字符。
好比我想匹配大括号."{}".我能够这样用:
console.log(/\{.+\}/.test("{123}")); //true
但事实上,量词还分为3种,有贪婪量词,惰性量词,支配性量词。
区分的依据是根据引擎的解析不一样而造成。
贪婪量词
这类量词指的就是上文所说的: *,+,?。
他的匹配方法就是,全文匹配,若是不成功,则,将末尾的最后一个字符减去,再匹配,若是还不成功,则,再减一次。只到为0。 接着,往中间移动一位,再进行匹配,一样的匹配模式。
console.log(/.+/.test("abcd")); //true
惰性量词
使用方法: 基本量词 ?
该量词和贪婪量词就像,一个是消极怠工,一个是积极工做。 惰性量词一开始只会匹配一个字符,若是不成功,则在进行匹配。
console.log(/\d+?/.test("1fjkdf")); //true
这里阐述一些惰性和贪婪匹配的区别。
咱们也一般把惰性称为最少重复匹配。
举个例子:
咱们如今须要匹配blablablabla. 中的b~a间的词。
使用贪婪匹配:
var str = "blablablabla"; console.log(str.match(/(b.*a)/g)); //["blablablabla"]
咱们最少重复匹配(惰性匹配)
console.log(str.match(/(b.*?a)/g)); //["bla", "bla", "bla", "bla"]
支配性量词
使用方法: 基本量词 +;
该量词就是只匹配一次,若是不符合则不匹配。
可是因为js不支持,因此,这里也不作过多的介绍。
正则: /\d*+/;
其实上面只要留个印象就能够,只有当你真正使用的时候,你才会有感触。
OK!!!基本内容说完了,如今轮到真正的进阶,big boom~
咱们从小学学过来,老师告诉咱们,咱们使用括号有3种,一个是( ),一个是[],一个是{}.
而在正则里面,大括号已经被量词字符给强占了,只剩下[]和(). 这里咱们来讲一下,中括号.
[],在正则里面表明的是一个单元字符,或者我宁愿叫他"或"括号. 由于他起到的主要做用就是,你能够匹配这个或者匹配那个或者...
吃个栗子:
var reg = /[abc]/; console.log(reg.test("a")); //true
能够看出,reg能够匹配 a|b|c. 日常使用的时候,能够直接向一个字符使用就能够了。
异或表达
这里会出现一个问题,好比,我不想匹配a,b,c中的任意一个该怎么办呢? 其实,只须要在"[]"里面加上"^"便可。
console.log(/[^abc]/.test("c")); //false
范围字符
范围字符,就是能够省略一些周所周知的。 好比匹配26英文字母能够直接使用:a-z. 由于咱们已经都知道了这个的意义。
其实,上面所说的字符类彻底就可使用中括号来代替。
\d => [0-9] \w => [0-9a-zA-Z_] \S => [^\t\n\x0B\f\r] (\f标识分页符) ...
另外这个范围字符还有一个好处,就是匹配中文。(电脑都是外国人发明的呀。)
console.log(/[\u4e00-\u9fa5]{1}/.test("艹")); //true
这就是中括号的经常使用用法。
小括号的主要做用其实就是分组。日常是用来提取匹配到的字符串。
分组使用
使用()对内容进行区分。
console.log(/(jimmy)+/.test("jimmy")); //true
并且,配合使用match方法,能够得到匹配到的内容.(这里不加括号也是能够的).
var name = "My name is Jimmy"; console.log(name.match(/(Jimmy)/g)); //["Jimmy"]
须要注意在括号里面写正则和没有括号的时候,是没有区别的。咱们能够在()内嵌套你想加的。(若是你想嵌套()的话,Sorry,这样并无什么卵用).
var name = "My name is Jimmy Jimy"; console.log(name.match(/(Jimm?y)/g)); //["Jimmy", "Jimy"]
候选(或)
这个就至关于将括号加上一个或的功能. 即,在()里面使用"|"进行分隔。
var name = "My name is Jimmy sam"; var reg = /(jimmy|sam)+?/ig; console.log(name.match(reg)); //["jimmy","sam"]
反向引用
这个名字我真心不理解,什么"反向"... 我宁愿叫作,给分组加上标识符。这个的主要功能,就是给匹配到的小括号加上数字,来代表他是第几个匹配到的。若是不加,则默认从左到右的顺序为1,2,3...
var reg = /(100)\1/; var reg2 = /(100)(99)(101)\1\2\3/; //1=>100,2=>99,3=>101
在js中,一般是和replace搭配,才有威力。
var reg = /(100) (99)/; var str = "100 99"; console.log(str.replace(reg,"$2 $1")); //99 100
总而言之, 小括号就是让你使用分组的匹配. 说回来,分组有什么用呢?
实际上就是让你的正则看起来更短而已.
看个demo你就懂分组的意义了:
var str = "name jimmy"; console.log(str.match(/\b(\w+)\b\s+\1\b/)); // 这里的\1 实际上就是前面的(\w+) //获得的结果为 null. 由于name 不能匹配到jimmy因此为null var str = "jimmy jimmy"; console.log(str.match(/\b(\w+)\b\s+\1\b/)); //获得的结果为 jimmy。 由于/w匹配到的为jimmy,因此为jimmy
上面那种方法叫作后向引用. 另外, 咱们还能够显示的使用命名. 即:\b(?<fetchWord>\w+)\b\s+\b\kfetchWord\b
这样,就能够达到, 内部正则的复用. 不过, 对不起, 在js中,只支持数组分组, 即, 按顺序分配序号。和上面demo同样.
不过在perl 系列的正则中是使用(?P< xx>) 和 g
咱们直接使用 "(...)"进行的匹配是捕获分组。 咱们来讲一下什么叫捕获. 上文中咱们使用match进行正则匹配,而返回的数组中的元素就是经过正则捕获的内容。 这就叫捕获。
那这里的非捕获,是什么意思呢? 其实很简单,就是经过match不会匹配到内容。但仍是能够起到分组的效果。
格式为: (?:xxx)
它最经常使用的地方就是匹配html.
var str=` <div class="pin"> <div class="box"> <img src="http://cued.xunlei.com/demos/publ/img/P_001.jpg" /> </div> </div>`; var reg = /<div(?:.|\r|\n)*div>/gi; console.log(str.match(reg));
你们能够去试一试,说到正则匹配,我还有一个想说的,就是上文所说的惰性匹配(最少重复)和贪婪匹配。
能够看到 “/< div(?:.|r|n)*div>/gi” 我这里使用的是贪婪匹配。他的结果是,尽可能匹配到最外层的< /div>标签。
即上面的结果为:
<div class="pin"> <div class="box"> <img src="http://cued.xunlei.com/demos/publ/img/P_001.jpg" /> </div> </div>
能够看出,贪婪匹配,对于两个重复的/div 他会匹配到最外一层。
那咱们使用惰性匹配试一试。
/< div(?:.|r|n)*?div>/gi
获得的结果为:
<div class="pin"> <div class="box"> <img src="http://cued.xunlei.com/demos/publ/img/P_001.jpg" /> </div>
能够看出少了一个< /div>,缘由就是,惰性匹配尽可能只会匹配到第一个重复的< /div>上面的。
因此,总结一下,在使用正则匹配的时候须要搞清楚到底何时用惰性,何时用贪婪,这点很重要。 贪婪会匹配最外层,惰性会匹配最里层。
前瞻分为正向前瞻和反向前瞻。(因为js只支持前瞻,因此后瞻只会提一下)。 他的做用就是,在匹配的字符后面,断言说后面必定符合个人正则。 (好饶~~)
算了,先说一下基本格式吧。
正则 | 名称 | 做用 |
---|---|---|
(?=exp) | 正向前瞻 | 匹配exp前面的位置 |
(?!exp) | 反向前瞻 | 匹配后面不是exp的位置 |
(?<=exp) | 正向后瞻 | 匹配exp后面的位置 |
(?< !exp) | 反向后瞻 | 匹配后面不是exp的位置 |
看不懂了吧,咱们来看一下详细的内容。
for instances:
var str = "happied boring"; var reg1 = /happ(?=ied)/g; var reg2 = /bor(?!ied)/; console.log(str.match(reg1)); //["happ"] console.log(str.match(reg2)); //["bor"]
从这个例子能够很容易看出前瞻后瞻究竟是什么了。
回到上面的匹配html的例子。
这里咱们有个需求,即只留下img标签,那么就可使用前瞻.
var str=` <div class="pin"> <div class="box"> <img src="http://cued.xunlei.com/demos/publ/img/P_001.jpg" /> </div> </div>`; var reg = /<(?!img)(?:.|\r|\n)*?>/gi; console.log(str.replace(reg,"")); //获得的结果为: <img src="http://cued.xunlei.com/demos/publ/img/P_001.jpg" />
另外,零宽断言还有另一个做用,即匹配以xxx为结尾的单词。
这时候,你的leader对你有个要求,即,jimmy呀,你把ed结尾的单词找出来哦。(好呀~)
这时候就可使用前瞻了。
var str = "he is an interested person"; var reg = /\b\w+(?=ed\b)/ig; console.log(str.match(reg)); //["interest"]
关于正则的内容大概就是这些了。 其实正则的学习,不是只用看就能学会的,实践才是硬道理。 经过,理论的学习,在加上踩过的坑,天然会对正则有着莫名的好感。 不过,大神就是大神,取名字就是这么别扭。 什么 零宽断言,前瞻,后瞻,反向引用 blablabla... 在理解的同时能够根据本身的理解给这些名词冠上本身的idea.我这里只是 正则的冰山一角,正则在任意一门语言内,用处都是超级大的。这里安利一个 总结的比较好的正则库。正则库. 还有一个在线的regExp测试工具.Debuggex