深入浅出,手把手教你编写正则表达式

30
日常代码的开发中,大家都或多或少的碰到一些正则表达式,但有的朋友只是会用,或者大致明白,希望这篇对正则深入浅出的文章能够让大家有所收获。

基本语法

[xyz]     一个字符集,匹配任意一个包含的字符
[^xyz]    一个否定字符集,匹配任何为包含的字符
\w (小写) 匹配字母或数字或者下划线的字符
\W (大写) 匹配不是字母,数字,下划线的字符
\s (小写) 匹配任意空白符
\S (大写) 匹配不是空白符的字符
\d (小写) 匹配数字
\D (大写) 匹配非数字的字符
\b (小写) 匹配单词的开始或结束的位置
\B (大写) 匹配不是单词开头或结束的位置
 $        匹配字符串的结束
 ^        匹配字符串的开始
 .        匹配所有,除了换行符
 -        重复0次或更多次
 -        重复1次或更多次
 ?        重复0次或一次
 {n}      重复n次
 {n,}     重复n次或更多次
 {n, m}   重复n次到m次
等更多.........

更多语法可以在W3C正则里查看

匹配位置

需要强调一下匹配位置的几个语法, 后面会一一举例说明
^ 匹配字符串的开始
$ 匹配字符串的结尾
(?=pattern) 正向前瞻,字符串匹配满足条件的位置
(?!pattern) 负向前瞻,字符串匹配满足条件的位置

常用方法和属性


正则表达式的写法有两种

var reg = new RegExp('/1/')
var reg = /1/

reg是正则对象的实例,通过console.dir打印对象,我们能看到实例上面的属性和方法。

clipboard.png

  • 常用的方法

举个简单的例子,我们来了解下test()和exec()的区别和使用场景。

var reg = /1/, reg1 = /(1)/
reg.test(1111) // true
reg.test(222) // false
reg.exec(11112) // ["1", index: 0, input: "11112"]
reg1.exec(11112) // ['1111', '1', index: 0, input: '11112']
reg1.exec(222) // null

test验证后会返回一个布尔值,主要用于验证是否匹配,exec则在验证成功后返回一个类似数组的对象,主要用于捕获分组,失败则返回null。

reg1是一个匹配(1)分组的正则,使用exec匹配成功后返回['1111', '1', index: 0, input: '11112'],input是输入的值,第一项是匹配满足条件的数据,第二项是匹配到的分组,如果没有分组,第二项则不存在,index属性则表示从第几项开始匹配到。
关于分组的话在下面会有详细的例子说明。

  • 常用的属性
 ignoreCase 忽略大小写,默认为false
 global     全局匹配,默认为false
 multiline  在有换行的时候,可以得到换行的起始位置和终止位置,默认为false

匹配规则

正则表达式(regular expression)描述了一种字符串匹配的模式,可以用来检查一个串是否含有某种子串、将匹配的子串做替换或者从某个串中取出符合某个条件的子串等

当当看描述和说明文档可能有点太官方化了,先假设我们已经都了解了正则匹配的基本语法和大致的使用,接下来这里用简浅的例子一步一步来分析怎样去实现自己需要的正则表达式。
  • 例子: 手机号码

首先举个例子,要匹配一个手机号码。先分析一下手机号码有什么样的规则呢,1开头,必须为数字,而且总共长度为十一位,那我们就有了下面这个表达式:

var reg = /^1[0-9]{10}$/ // 根据正则语法 ^为匹配开始,^1就表示第一位必须为1开头,[0-9]指的是必须为0-9的数字,{10}表示重复次数为10,$结束符。简单的匹配规则完成。

好像有点粗糙,一般手机号码第二位是不会有0-9这么多的可能的,所以我们需要在优化一下,第一位为1,第二位为[3,5,8,7]:

var reg = /^1[3,5,8,7]{1}[0-9]{9}$/ // 根据正则语法 ^为匹配开始,^1就表示第一位必须为1开头,[3,5,8,7]指的是匹配其中任一数字,{1}表示重复次数为1,前两位匹配完成,加上后面的[0-9],{9}重复九次,$结束符。简单的匹配规则完成。

这样,基本的一个手机号码的正则匹配规则就出来了,如果自己业务有需求,做相对应的改动就可以了。

  • 例子:邮箱

和手机号码的规则相比较,邮箱的匹配规则稍微复杂一点。同样,我们先分析邮箱的规则,比如QQ邮箱,110@qq.com,先有字符,长度大于1,然后是@,后面再跟着一串字符长度大于1,那我们就可以得到这样一个的表达式:

var reg = /^[\w\.]+@[\w.]+$/ // [\w\.] \w匹配字母或数字或者下划线的字符,\.通过转义符表示匹配.,+表示重复一次或更多次,匹配@符号,然后又是同样的\w\.匹配一次或更多次。
  • 例子:网站

同样是分析网站规则,http(s)://segmentfault.com/1233, 首先可能是http协议或者https协议,然后是://,然后是字符串。这样一分析,再把对应的正则语法理一理,很快一个匹配规则就出来了:

var reg = /^https?:\/\/.+$/ // 首先会是http开头,^http, 然后s跟随?表示匹配0次或一次,:,//需要用\转义,后面跟随各种类型的不确定因素.+,当然,如果我们要做的更精确的匹配,则可以修改成自己的规则即可。

举了几个基本的例子,让我们去复习巩固正则的基本使用和匹配规则,首先分析要匹配的规则是什么,然后一步一步去把规则拼积木一样拼进去,就可以了,自己多定义一些不一样的规则然后去一个一个实现,就会发现如果只是基本的使用,远没有想象中的难。

分组

分组的就是把要匹配的规则分成一个组,写在()里,比如匹配数字(0-9),匹配字母(0-z),主要有分为捕获型分组和非捕获型分组。

  • 捕获型分组

先来说说捕获型分组。主要可以干的事情有两个,引用和反向引用,在一些稍微复杂的正则表达式里,我们常常会用到这些。

  • 捕获型分组-引用

在每次分组捕获之后,RegExp对象上面可以拿到最近捕获到的分组,下面来举一些例子:

var reg = /(1)(3)/ // 两个分组
reg.exec(123134) // 捕获到了两个分组
console.log(RegExp.$1) // 1
console.log(RegExp.$2) // 3

得到到了最近捕获的分组,可是往往我们不明白捕获到了分组有什么用,下面举个例子,将所有的html标签替换成p标签,来说明捕获到的分组怎么去引用。
首先我们分析一下这个匹配的规则,开始标签为<字符串>,结束标签为</字符串>,我们只需要把这些替换为<P> </p> 就可以了。

var str = '<span>1234</span><div>456</div>'
var reg = /<(\/?)(\w+)>/g  // 先匹配<,然后(/?)重复0或一次,然后匹配\w+,匹配>,结束。
str.replace(reg, '<$1p>')  // 字符串的替换方法,这里使用了$1,就是RegExp.$1,引用正则里面的分组(\/?),
                           // 所以<$1p>中的$1则为动态捕获到的分组。当标签为</元素>时,RegExp.$1为/,
                           // 字符串中用</p>替换原来标签,
                           // 则达到了将html字符串中开始标签和闭合标签全部替换的效果
  • 捕获型分组-反向引用

反向引用也是一样将捕获到的分组引用,不过是在编写的正则里面,通过/1,/2,/3可以得到当前捕获到的分组.

  • 非捕获型分组

(?:)即表示该分组不能被捕获,之后在引用的时候是引用不到这个分组的。

贪婪匹配和惰性匹配

正向前瞻和负向前瞻


如果觉得我的文章对你有用,请随意赞赏

你可能感兴趣的

高压郭 · 1月12日

开头就看到写错了,是$匹配结束,^匹配开头

回复

0

之前的笔记写错了,直接复制过来的 哈哈

我在长安长安 作者 · 1月13日
载入中...