一。概述
引入:
1.从一个文章中找到所有的邮箱
2.看看输入的手机号收不是符合手机号的规则
3.检查输入的是不是身份证号
正则表达式:又称规则表达式,是一种文本模式。正则表达式使用单个字符串来描述,匹配有相同规则的字符串,通常用来检索替换那些符合某个模式(规则)的文本。正则表达式的核心功能就是处理文本。
正则表达式不仅限于一种语言,但是在每种语言中有细微的差别。
二。正则表达式的基础语法
每一个字符串都可以被视为一个简单的正则表达式 ,例如hello world正则表达式匹配“hello world”字符串。有的人可能觉得这不是废话嘛,但是有些特殊的字符或者特殊的表达式,它可以进行一些泛化。比如\d可以表示任意数字。
1.元字符
元字符是构造正则表达式的一种基本元素。
.:匹配换行符之外的任意字符。
\w:匹配字母,数字,下划线
\s:匹配任意的空白符
\d:匹配数字
^:匹配字符串的开始
$:匹配字符串的结束
案例:
匹配8位数字的QQ号:^\d\d\d\d\d\d\d\d$
匹配1开头的11位数字的手机号码:^1\d\d\d\d\d\d\d\d\d\d$
2.重复限定符
正则表达式提供了对重复字符进行简写的方式:
*:重复零次或更多次
+:重复一次或者多次
?:重复零次或者1次
{n}:重复n次
{n,}:重复n次或者更多次
{n,m}:重复n次到m次
案例,我们对上面的案例进行优化:
匹配8位数字的QQ号:^\d{8}$
匹配1开头的11位数字的手机号码:^1\d{10}$
匹配以a开头,0个或多个b结尾的字符串:^ab*$
3.分组
限定符是作用在与他相邻的最左边的一个字符,那么问题来了,如果我想要ab被同时限定那怎么办?正则表达式中使用小括号()来进行分组,也就是说括号中的内容会被当成一个整体。
案例:
匹配字符产中包含0到多个ab开头:^(ab)*$
4.转义
正则提供了转义的方式,就是要把这些元字符,限定符或者关键字转译成普通的字符,做法很简单,就是在需要转移的字符前面加个"\"就好。
案例:
匹配字符串中包含0个或者多个(ab)开头:^(\(ab\))*$
匹配一个字符*:\*
5.条件
回到我们刚才的手机号匹配,我们知道,国内的号码都来自于三大运营商,他们的手机号都有属于自己的号段,比如联通的130/131/155/185/186/145/176等号段,如果让我们去匹配一个联通的号码该怎么办呢?
正则表达式用符号|来表示或,也叫分支条件,当满足条件中的任何一个分支时候都会被当成事匹配成功。
案例:
匹配联通的手机号:^(130|131|155|156|185|186|145|176)\d{8}$
6.区间
正则表达式提供一个中括号[]来表示区间条件。
限定0-9可以写成是[0-9]
限定A-Z可以写成是[A-Z]
案例:
匹配联通的手机号:^(13[01]|15[5-6]|18[5-6]|145|176)\d{8}$
7.反义
前面说到元字符都是你想匹配到什么,当然也可以反着来,不想匹配某些字符,正则表达式也提供了一些常见的反义字符
\W:匹配任意不是字母,数字,下划线的字符
\S:匹配任意不是空白字符的字符
\D:匹配任意非数字的字符
\B:匹配不是单词开头或者结束的位置
[^X]:匹配除了X以外的字符串
[^aeiou]:匹配除了aeiou这几个字母以外的字符
8.常见的正则表达式
匹配中文汉字:[\u4e00-\u9fa5]
三。进阶语法之零宽断言
1.零宽断言
断言:就是说正则可以断定在指定内容的前面或者后面会出现满足指定规则的内容。
零宽:断言部分之确定位置不匹配任何内容,只是一种模式,内容的宽度是0
我们举个例子:假设我们要用爬虫爬取csdn里面的文章阅读量,通过查看源代码可以看到文章阅读量这个内容结构是这样的:“<span>阅读数:641</span>”,其中也就641这个是变量,也就是说不同的文章不同的值,当我们拿到这个字符串的时候,就可以使用到零宽断言。下面我们讲解零宽断言的几种类型:
预测/先行:模式在前,要求后面的符合匹配
回顾/后发:模式在后,要求前面的符合匹配
正:符合匹配
负:不符合匹配
2.正向先行断言(?=pattern)
用来匹配pattern表达式前面的内容,不返回本身。
案例:
获取阅读量的数字:“\d+(?=</span>)”
3.正向后发断言(?<=pattern)
用来匹配pattren表达式后面的内容不返回自身
案例:
获取阅读量的数字:(?<=<span>阅读数:)\d+
3.负向先行断言(?!pattren)
用来匹配非pattren后面的内容,不返回本身
案例:
“人间归离复归离,借一浮生逃浮生。”
我要找不是逗号前面的归离:归离(?!,)
4.负向后行断言(?<!pattern)
匹配非pattern表达式的后面内容,不返回本身。
案例:
“人间归离复归离,借一浮生逃浮生。”
我要找不是逃后面的浮生:(?<!逃)浮生
四。进阶语法之捕获组
捕获组:我们匹配子表达的内容,并把匹配结果[以数字编号或组名的方式]保存到内存中,之后可以通过序号或者名称来使用这些匹配结果。
1.数字编号捕获组:
语法:(exp)
解释:从表达式左侧开始,每出现一个左括号和它对应的右括号的内容被称为一个分组,在分组中第零组是整个表达式,第一组开始为分组。
案例:
比如固定电话020-85653333
正则表达式是:(0\d{2})-(\d{8}) 前面是区号,后面是电话号。
上面的表达式分组如下:
编号 分组 内容
0 (0\d{2})-(\d{8}) 020-85653333
1 (0\d{2}) 020
2 (\d{8}) 85653333
2.命名编号捕获组
语法:(?exp)
解释:分组的命名由表达式中的那么指定,比如区号可以这样写:
(?<aNumber>0\d{2})-(?<pNumber>\d{8})
编号 名称 分组 内容
0 0 (0\d{2})-(\d{8}) 020-85653333
1 aNumber (0\d{2}) 020
2 pNumber (\d{8}) 85653333
3.非捕获组
语法:(?:exp)
解释:和捕获组刚好相反,他用来标识那些不需要捕获的分组。比如上面的表达式,程序不需要用到第一个分组,就可以这样写:(?:0\d{2})-(\d{8})
编号 分组 内容
0 (0\d{2})-(\d{8}) 020-85653333
1 (\d{8}) 85653333
4.反向引用
我们知道,捕获会返回一个捕获组,这个分组时保存在内存中,不仅可以在正则表达式外部通过程序进行引用,也可以在正则表达式的内部进行引用,这种引用方式就是反向引用。反向引用可以分为:
普通捕获组反向引用:\k<number>,通常简写成 \number
命名捕获组反向引用:\k<name>,或者\k'name'
案例:
我们要找到aabbdidufhsnjjadffaww里面成对的字母。
思路:1.首先匹配一个字母\w,我们需要做成分组才能捕获,因此写成这样(\w)。2.然后我们用这个捕获组作为条件,就可以(\w)\1
五.贪婪和非贪婪
贪婪匹配:当正则表达式中包含能接受重复的限定符时,该方式匹配尽可能多的字符,这种匹配方式叫做贪婪匹配。前面我们讲过重复限定符,其实这些重复限定符就是贪婪量词,比如表达式\d{3,6}用来匹配3-6个数字,在这种情况下,它是一种贪婪模式的匹配,也就是假如字符串里有6个数字可以匹配它可以全部匹配到,他优先匹配6个不是3个。
当多个贪婪量词在一起时,如果字符串能满足他们各自的最大的匹配时候,就互不干扰。但是如果不能满足时,会优先满足最大数量的匹配,剩下的再去分配下一个量词匹配。
非贪婪匹配
非贪婪量词就是在贪婪量词后面加上个?:
*? 重复人一次,但是尽可能少重复
+? 重复1次或者更多次,但是尽可能少重复
?? 重复0次或者1次,但是尽可能少重复
{n,m}? 重复n次到m次,但是尽可能少重复
{n,}? 重复n次以上,但尽可能少重复