【正则表达式系列】入门篇

作者 BiYuqi 日期 2017-11-26
【正则表达式系列】入门篇

开始之前,我希望你能放下心中的恐惧感!

前言

对于一个刚接触正则的人来说,会让人觉得那么神秘,闻而生畏。

正则想要精通更是不易,需要大量反复的练习,接触正则也不少时间了,不知怎么的,我就自己走过了那段畏惧正则的时期,日常的中遇到的问题基本上都能解决

由于笔者是从事于前端开发的,所以本文中的正则都是基于Javascript的语法规则也讲述,不过不同语言之间的正则基本是相通的,只是语法表示上有点区别,我计划总结下我的一下学习的经历和心得:

【正则表达式系列】入门篇

【正则表达式系列】贪婪与非贪婪模式

【正则表达式系列】零宽断言篇(待写)

正文

正则字符,很多文章都会讲到,篇幅原因我就不多说,我只列举常用的:

元字符

元字符 描述
. 匹配除换行符以外的任意字符
\d 匹配数字, 等价于字符组[0-9]
\w 匹配字母, 数字, 下划线
\s 匹配任意的空白符(包括制表符,空格,换行等)
\b 匹配单词开始或结束的位置
^ 匹配行首
$ 匹配行尾

反义元字符

元字符 描述
\D 匹配非数字的任意字符, 等价于[^0-9]
\W 匹配除字母,数字,下划线之外的任意字符
\S 匹配非空白的任意字符
\B 匹配非单词开始或结束的位置
[^x] 匹配除x以外的任意字符

重复限定符

限定符 描述
* x>=0
+ x>=1
? x=0 or x=1
{n} x=n
{n,} x>=n
{n,m} n<=x<=m

修饰符

javaScript中正则表达式默认有如下五种修饰符:

  • g (全文查找), 如上述截图, 实际上就开启了全文查找模式.
  • i (忽略大小写查找)
  • m (多行查找)
  • y (ES6新增的粘连修饰符)
  • u (ES6新增)

常用几个字符解释

1. .匹配不包括换行的任意字符

如果需要匹配包括换行的任意字符,可以使用[\s\S]来代替.

2. \s空格、tab、换行

[\s\S]表示匹配任意字符,\S\s的反义。注意区分[\s\S].的区别。

3. *匹配零个或更多个,即0~n

4. +匹配一个或更多个,即至少一个,1~n

5. \ 转义

一个特殊字符前加\就表示转义,说明把它当普通字符用

6. []单字符取一个,比如[abc]会匹配a或b或c

如果[]里面加上^则会变成排除这个字符,比如[^abc]就是既不包含a,也不包含b,也不包含c
[]里可以使用-来表示一个范围,[0-9]表示从0到9,[a-zA-Z]包含26个字母,如果要包含-则要加上转义字符[\-]
[]常见的错误用法是:[ab|bc]用来表示ab或bc,实际上,它得到的结果是[abc|],即匹配的是a或b或c或|这4个字符(单字符)的任意一个。这里可以改成(ab|bc)
总结:[]里面的特殊符有五个:[]-\^,其他字符都是普通字符,包括*.?等。

  • ^[^ 的首位时候才有特殊意义
  • [0-9 -在不是首尾的时候有特殊意义
  • \本身是转义符,有特殊意义

7. ^ 字符串开始

注意区分,不在[]里面的是开始符,在里面的是排除
eg: ^http vs [^abs]

8. ? 有两个用法

  • 匹配一个或零个
    eg: https?匹配https(一个s)或者http(零个s)
  • 非贪婪模式
    所谓非贪婪模式,就是匹配尽可能少的内容,比如,对于源字符串
<div>a</div><div>b</div>

使用<div>(.*?)</div>会得到2个结果(注意:如果源字符串有换行,使用[\s\S]替换 .

<div>a</div>


<div>a</div>

因为,当遇到第一个</div>,非贪婪模式就不会再往后找了。
而使用<div>(.*)</div>(贪婪模式)则会得到整个字符串,因为它会匹配所有字符直到后面再找不到

<div>a</div><div>b</div>

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

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

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

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

13. | 多个数据选一(常用于多字符)

前面提到[]里面的字符有选一个字符功能,但是假如不是一个字符,比如:http|git|svn 就需要用|分开,|的作用域是一直往后直到遇到括号,比如,对于源字符串
匹配:

  • http abc
  • git abc
  • svn abc

就可以直接使用(http|git|svn)abc来进行匹配

14. () 数据分界和取数据

(http|git|svn)abc就是一个分界的例子,匹配结果会得到一个数组集合,其中[1]也就是数组的下标1得到的是一个数组集合,这就是模式匹配,也叫分组,子模式计数是从左至右
(https?):\/\/([^\/]+) 就是一个匹配网址的正则,其中分组2得到的是网址主地址;

/(https?):\/\/([^\/]+)/.exec('http://loadingmore.com')[2] // loadingmore.com

点击这里查看匹配情况

15. (?:)非捕获组

上面提到的()作为子模式可以得到里面的数据,但是有些时候我们只是把它作为分界,不需要取数据,这个时候就需要用到非捕获概念了。比如上面匹配网址需要在分组2才能得到loadingmore.com,分组1是http;这个时候我们只需要后面的网址,就可以用非捕获来实现(?:https?):\/\/([^\/]+)

/(?:https?):\/\/([^\/]+)/.exec('http://loadingmore.com')[1] //loadingmore.com

点击这里查看匹配情况

16. 模式修饰符

模式修饰符很多语言都支持,js中常用的比如i不区分大小写,g全部匹配,m是多行匹配

const reg = /a-z/i // 可以匹配26字母 不区分大小写
const reg2 = /http/g // httphttphttp可以匹配三个http,没有g修饰,只能匹配第一个

简单操作练习

定位

下面就一段html进行剖析
目标:得到 target1中inner内容 哈哈1

<div class="target1">
<div class="inner">
哈哈1
</div>
</div>
<div class="target2">
<div class="inner">
哈哈2
</div>
</div>

写正则之前,首先要观察要匹配的数据结构,找出异同点,精准定位到你想要数据的位置,必须你需要一个页面的title的内容,那么title就是你的正则的关键字,所要取的数据确实无法定位一个唯一的锚点,那就可以采用分段取数据,缩小范围后,再对这个数据进行二次分解
比如上面的html片段,加入直接采用:

// 很明显会得到两个inner数据段
const reg = /<div\s+class="inner">([\s\S]+?)<\/div>/

点击查看详情
这个时候我们就可以考虑以class=”target1”作为定位点进行匹配

const reg2 = /<div class="target1">\s+<div class="inner">([\S\s]+?)<\/div>\s+<\/div>/

点击查看详情

tips:采用[\s\S]+原因是html结构有换行;.不符合要求,.匹配不包括换行的任意字符,[\s\S]+?加?号的原因是非贪婪模式,否则会一致直匹配到不能匹配为止,本文只需要第一个,所以采用非贪婪模式匹配。下文会讲到贪婪与非贪婪模式

总结:所谓匹配数据,就是找到能唯一定位你数据的标识的锚点

去噪音

所谓去掉噪音,就是把哪些无关紧要的,迷惑你的数据果断抛弃掉,一眼抓住你想要的那个字符即可,比如:

<a data-v-1b4073f4="" href="https://github.com/icepy/Front-End-Develop-Guide#fed_point_recommend" target="_blank">前端开发指南</a>

找出上个连接中的href链接,当然了,这用js的dom元素获取轻而易举,本文只是为了做示范,阐述一种正则思维

// 首先要定位 <a href= 还有链接后面的 ” 其他的都不用关注
cosnt str = `<a data-v-1b4073f4="" href="http://loadingmore.com" target="_blank"></a>`
const reg = /<a[^>]*?href="([^"]+)"/
const result = reg.exec(str)[1]
// console.log(result)

点击查看详情
总结:关心的留下,不关心的都是浮云

取数据

关于取数据一般都用到分组捕获上文有提及

最后的话

学习正则,一定要多练习,狠下心来,过一遍正则基础,收获绝对满满,一边下来,不知不觉就掌握了大部分,当然了想要精通,爱需要深入的学习和大量练习,持之以恒方得成效

附录

正则表达式30分钟入门教程
1小时教你学会正则表达式