【正则表达式系列】快速入门

| 分类 blog  | 标签 正则表达式  元字符  快速入门  | 浏览  
正则表达式

引言

首先,请抛下心中的畏惧与反感!

关于正则不得不说的话

正则表达式难么?

想要精通它,确实不容易,需要大量的反复练习 但是如果仅仅是入门,能写一些简单的表达式(譬如邮箱验证之类的),达到这点是不难的,而且大部分的人的刚需还是这些简单的表达式

但是实际中,初学正则时一看到MDN以及各大教程上的复杂介绍,立马就蒙圈了,久久不能自已 因此初学时,入门指南需要尽量浅显易懂(本文末尾的参考来源中也有部分不错的教程,可以直接参考学习)

本文中,采用JavaScript为基础语言,优先进行正则表达式的简单校验,而不是提取以及更复杂的工作 正常看完本文,一些简单的正则表达式应该是不在话下了(譬如邮箱验证等)

另外,如果是新手入门,请至少花上半小时,可以优先看简单场景的正则练习 还有就是,本文中列举的元字符是属于必须掌握的级别,否则没有可能入门甚至精通正则

大纲

  • 最核心的几个元字符

  • 简单场景的正则练习

  • 常见场景的正则应用

最核心的几个元字符

  • abc 匹配包含abc字符串

  • ^begin: 匹配以begin开头的字符串

  • end$: 匹配以end 结尾的字符串

  • a* 字符a出现0次或者更多次,等价于{0,}

  • a{0,} 字符a出现0次或者更多次

  • a{3} 字符a出现3次,不能多也不能少

  • a+ 字符a出现1次或者更多次,等价于{1,}

  • a{1,} 字符a出现1次或者更多次

  • a? 字符a出现0次或者1次,等价于{0,1}

  • a{0,1} 字符a出现0次或者1

  • (ab){0,1} 字符ab出现0次或者1次,也就是说ab一起匹配

  • a.b 字符a与字符b之间可以是任意字符(\n除外)

  • (a│bc|d)e 可以是ae或者是bce或者是de

  • [ab] 匹配单个的a或者b(中括号中只会匹配其中一个单词)

  • [a-d] 匹配ad之间的某一个单词(包括a和d)

  • %[^a-zA-Z]%[]内的^代表排除里面的字符,例如这个代表以%开头,并以%结尾,并且中间是非字符的字符串

  • \w 匹配任意单词(包括下划线),但是-等不再范围内,等价于[A-Za-z0-9_]

  • \d 匹配任意数字。等价于[0-9]

上述元字符在简单的场景应用中基本已经足够了,因此掌握了它们后,不要立马继续学习更高深的内容,而是应该先用它们进行组合,完成简单场景下的应用

要点

  • ^用在中括号开头的时候,就表示排除括号里的字符

  • 在中括号里面, 所有的特殊字符,都将失去他们的特殊性质,例如 [*/+?{}.] 为匹配含有这些特殊字符的字符串(\ 除外,这个会转义所有字符)

  • []中如果包含-,最好把它放在最前面或者最后面(否则可能会被当成连字符)

  • \特殊字符 代表去这个字符本身,例如\.代表匹配.这个字符

简单场景的正则练习

匹配abc字符串,不能多也不能少

var reg = /^abc$/;

reg.test('abc'); // true
reg.test('abcd'); // false
reg.test('dabc'); // false

要求以abc开头,并且以abc结尾,那么就只有abc本身符合要求了

匹配a*b.178 这个字符串

/^a\*b\.178$/.test('a*b.178'); // true
/^a[*]b[.]178$/.test('a*b.178'); // true
/^a[*]b[.]178$/.test('a*c.178'); // false

\ 或者 []包围都能取到特殊字符

匹配a*ba/ba+ba-b 中的任意一个字符串

/^a[*/+-]b$/.test('a*b'); // true,换为+  -  /  也一样为true
/^a(\*|\/|\+|\-)b$/.test('a*b'); // true,其它结果同上

这里可以看出,一些简单的场景下,用[]来写会更为简介易懂(因为\ 这个字符很干扰视线)

匹配以.js结尾的字符串,但是不能只是.js

var reg = /.+[.]js$/;

reg.test('a.js'); // true
reg.test('-.js'); // true
reg.test('.js'); // false

/\w+[.]js$/.test('-.js'); // false

上述表达式中,用了.+ . 代表匹配任意字符(\n除外) + 代表至少匹配一次 另外,下面那个\w代表只匹配单词(包括下划线),因此-被排除在外了

匹配.min.css结尾的css文件

var reg = /\w+[.]min[.]css$/;

reg.test('a.min.css'); // true
reg.test('.min.css'); // false
reg.test('-.min.css'); // false
reg.test('测试.min.css'); // false

这里上述用来匹配时用到了\w,代表只匹配合法英文单词开头的.min.css文件

匹配字符串是否是纯数字组成

var reg = /^[0-9]+$/;

reg.test('123'); // true
reg.test('12s3'); // false
reg.test(''); // false

上述匹配。只允许出现纯数字,并且只是出现一个,不能为空

匹配一个非0开头的非负整数,但可以是0本身

var reg = /^(0|[1-9][0-9]*)$/;

reg.test('123'); // true
reg.test('0'); // true
reg.test('01'); // false

这个表达式使用了|()以及[]* 首先,0|(表达式2)代表取0本身或右边那个表达式2 而表达式2中的[1-9][0-9]*代表以1-9中的某个数字开头。接下来有0-9中的数字可以出现0次或更多次,也就是说10或者1010或者更多的数字在后面出现都可

常见场景的正则应用

上述的简单场景练习完毕后,基本正则的用法都应该知道了,下面针对一些常见场景的应用继续进行练习

匹配一个10进制数字

验证规则

  • 可以是整数或者浮点小数

  • 可以是负数

  • 除了0本身,不能以0开头

代码

var reg = /^-?(0|([1-9][0-9]*)+)(\.[0-9]+)?$/;

reg.test('0'); // true
reg.test('-0'); // true
reg.test('10.10'); // true
reg.test('0.1'); // true
reg.test('-0.1'); // true
reg.test('0.0'); // true
reg.test('101'); // true

reg.test('00.1'); // false
reg.test('.1'); // false
reg.test('001'); // false
reg.test('-.1'); // false

详解

这个场景相对来说算是比较复杂的乍看之下正则表达式很长很难理解,但其实我们可以将之拆分为两部分: 整数部分小数部分

  • 整数部分为-?(0|([1-9][0-9]*)+),其中由-?(0|([1-9][0-9]*)+)组成

    • -?代表-出现0次或1次,即可以是正数也可以是负数

    • (0|([1-9][0-9]*)+) 在简单场景中已经遇到过,代表0或者一个非负整数

  • 小数部分为(\.[0-9]+)?,由\.[0-9]+以及最后的?组成

    • \.代表.这个字符

    • [0-9]+ 代表0-9字符最少出现一次

    • ? 代表前面的表达式出现0次或1

    • 因此(\.[0-9]+)?代表小数部分可以存在或者不存在,如果存在,则小数部分必须有数字,例如.123合法,而.123不合法

  • 最终整数部分和小数部分结合就是上述的完整表达式

验证是否是有效的EMAIL邮箱

验证规则

  • 分为两部分组成前缀部分@域名部分

  • 前缀部分由字母数字、下划线_、短线-、点号.组成

    • 其中,不能以-.开头和结尾

    • 两个.之间必须有字符

    • 两个-之间必须有字符

    • -.之间必须有字符

    • 例如abcd_s.ddf.ff-sss

  • 域名部分为一个域名,由 N级别域名.(三级域名.二级域名.顶级域名)组成

    • 其中N级别域名为至少要有一个合法单词(单词数字或下划线)

    • (三级域名.二级域名.顶级域名) 每一部分由合法单词组成,并且每一部分不能少于2位,不能大于4

    • (三级域名.二级域名.顶级域名) 只能是如下组合情况: 顶级域名二级域名.顶级域名三级域名.二级域名.顶级域名

    • 例如 gmail.comvip.qq.com,另外app.ep.gt.com这种也需要通过验证

代码

var reg = /^(\w)+([-.]\w+)*@(\w)+((\.\w{2,4}){1,3})$/;

reg.test('abcd_s.ddf.ff-sss@qq.com'); // true
reg.test('abcd_s.ddf.ff-sss@abc.vip.qq.com'); // true

reg.test('abcd_s.ddf.ff-sss@abc.vip11.qq.com'); // false
reg.test('abcd_s.ddf.ff-sss@a.abc.vip.qq.com'); // false
reg.test('abcd_s.ddf.ff-sss@abc.v-p.qq.com'); // false
reg.test('abcd_s.ddf.ff-sss@.com'); // false
reg.test('abcd_s.ddf.ff-sss@com'); // false

reg.test('-dai@qq.com'); // false
reg.test('dai.@qq.com'); // false
reg.test('d--ai@qq.com'); // false
reg.test('d..ai@qq.com'); // false
reg.test('d-.ai@qq.com'); // false

详解

可以说,如果能写出这个正则表达式,就已经算入门了,因为已经掌握基础了,剩余的高级知识,可以慢慢的学习,积累,扩充到自己的知识体系中

这个正则验证规则描述起来很长,但实际上最终的表达式并不复杂(如果真的掌握了基础的话),仍然可以分为两部分前缀部分域名部分

  • 前缀部分表达式为: (\w)+([-.]\w+)*

    • \w代表以一个合法字符开头(因为不能.-开头)

    • (xxx)* 代表这一部分可以不存在,也可以有无数个

    • [-.] 代表-.只能二选一

    • \w+代表至少要有一个合法单词,这样确保了-.后面至少会跟一个单词,和前面的[-.]一起组合,排除了---...等的可能,排除了-.结尾的可能

    • 所以这时候就已经完成了: 以合法单词开头,可以有-.,不能以-.结尾,-.之后必须跟一个合法单词,至此前缀部分表达式已经完成

  • 域名部分表达式为: (\w)+((\.\w{2,4}){1,3})

    • (\w)+代表前面的N级别域名至少要有一个合法单词,但是不做数量上限

    • (\.\w{2,4}) 代表域名的单词不能少于2个,不能大于4

    • (域名){1,3} 代表不能少于1次,不能大于3次,所以最少也要有顶级域名,最多就到三级域名

    • 至此,域名部分的表达式也编写完成

  • 当然了,上述的正则表达式是针对英文邮箱的,关于一些其它的中文字符等就不在这里的考虑范围,而且这个表达式已经完全可以匹配平时使用的邮箱了

写在最后的话

请不要畏惧正则表达式,如果真的狠下心来,系统的过一遍正则表达式基础,收获会非常之多,也许你工作好几年都没能掌握的正则表达式,就在你过一遍基础的情况下,不知不觉的掌握了

当然了,入门容易,精通难,如果入门了,接下来就是需要深入学习,加上大量练习,只有持之以恒才能真正的精通

附录

参考资料

上一篇     下一篇
Lichun Dai

Lichun Dai

程序员,偏前端。会点口琴和吉他。

博客 62 项目 2 随笔 108

GitHub 5sing 知乎 segmentfault 掘金