.NETCore :正则表达式
本节内容为正则表达式的使用
简介
有的时候,你是否有过这种需求:判断一个Ip地址、邮箱、密码规则是否合法。如果让你使用if一类的传统方法进行处理,你肯定会被逼疯的。而对于绝大多数的编程语言而言,都有一个字符串处理利器————正则表达式。它可以轻松的让字符串和规则匹配上。有点这样的意思,从前你是判断字符串,去遍历它,而有了正则表达式,你是在书写一个通用性质的规则,让字符串与规则进行匹配。正则表达式本质上就是一串蕴含了一些特殊字符规则的字符串,因此我们书写正则表达式其实是在书写一个字符串,只是它代表了一定的规则而已。
常见的几种正则符号
事实上正则表达式没有过多的知识点,只是一些技巧性的训练,但请相信我,正则表达式是非常重要的。熟练的使用下列的正则符号会对你大有脾益。
元字符
元字符 | 说明 |
---|---|
. | 匹配除了换行符以外的任意字符 |
\w | 匹配字母、数字、下划线以及汉字 |
\s | 匹配任意空白符 |
\d | 匹配数字 |
\b | 匹配单词的开始或结束 |
^ | 匹配字符串的开始 |
$ | 匹配字符串的结束 |
1.例如匹配abc开头的字符串
\babc 或者 ^abc
2.匹配5位数字的字符串
^\d\d\d\d\d$
重复限定符号
有了元字符就可以写不少的正则表达式了,但细心的你们可能会发现:别人写的正则简洁明了,如果你只使用元字符进行正则表达式的书写,既不美观也不实用,因此我们使用重复限定符进行重复数据的处理,下面我们来看一些限定符:
字符 | 说明 |
---|
- | 重复0次或多次
- | 重复一次或一次以上
? | 重复0次或一次
{n} | 重复n次
{n,}| 重复n次或更多次
{n,m}| 重复n到m次
现在我们就能书写相当美观的正则表达式了,例如:
1.匹配7位数字的电话号码
^\d{7}$
2.匹配138开头的手机号
^138\d{8}
3.匹配a开头,若干个b结尾的字符串
^ab*$
分组
现在我们已经学会以一点关于书写正则表达式的方法,不过,我们现在无论是匹配还是重复都是针对单个字符进行操作,假如说我希望匹配一个以ab为循环的重复字符串应该如何去处理呢?
答案很简单,就是分组,分组我们通常使用()进行分组,例如匹配以ab为循环的字符串为:
^(ab)*
转义字符
有的时候,我们需要匹配的字符串中本身就含有正则表达式中的关键字符,我们则需要转义,例如我们需要匹配(ab)为循环的字符串:
^(\(ab\))*
反斜杠\就是我们的转义字符。不过对于C#中,字符串含有反斜杠会自动转义,为了避免这种情况,我们需要在字符串之前加上@或者将将转义字符转义,也就是\两个斜杠
条件或
有的时候,我们需要匹配的字符串可能是ab开头也有可能是cd开头,这个时候我们就使用条件语句处理,例如:
^(ab|cd)*
用逻辑或“|”进行处理。
区间匹配
有的时候,我们有可能是需要匹配比如说138-150之间所有数字开头的字符串,或者说A-F按字母表顺序内的字母开头,我们可以这样
^[138-150]*
^[A-F]*
反义
之前我们谈论的都是字符串中含有什么什么,现在我们可能需要匹配到字符串中不含有的字符,那么我们就需要使用反义,如下表
元字符 | 说明 |
---|---|
\W | 匹配不是字母、数字、下划线以及汉字 |
\S | 匹配不是空白符 |
\D | 匹配不是数字 |
\B | 匹配不是单词的开始或结束 |
[^x] | 匹配出了x以外的任意字符 |
贪婪模式与懒惰模式
贪婪
贪婪是当正则表达式中包含能接受重复的限定符时,通常的行为是(在使整个表达式能得到匹配的前提下)匹配尽可能多的字符,这匹配方式叫做贪婪匹配。特性:一次性读入整个字符串进行匹配,每当不匹配就舍弃最右边一个字符,继续匹配,依次匹配和舍弃(这种匹配-舍弃的方式也叫做回溯),直到匹配成功或者把整个字符串舍弃完为止,因此它是一种最大化的数据返回,能多不会少。
事实上我们之前所谈论的重复限定符就是一种贪婪量词
举个例子例如我们需要匹配由2-5个数字组成的字符串,假设有这样一串数字51354 8454 1 568,使用^\d{2,5}进行匹配的结果是51354 8454 568,事实上对于这些而言,匹配两个就已经满足了,例如51已经满足该正则式,但是在贪婪匹配中,它会尽可能的多匹配,将整个字符串输出。
如果多个贪婪量词叠加在一起,如果字符串能满足他们各自最大程度的匹配时,就互不干扰,但如果不能满足时,会根据深度优先原则,也就是从左到右的每一个贪婪量词,优先最大数量的满足,剩余再分配下一个量词匹配。
懒惰
懒惰匹配:当正则表达式中包含能接受重复的限定符时,通常的行为是(在使整个表达式能得到匹配的前提下)匹配尽可能少的字符,这匹配方式叫做懒惰匹配。特性:从左到右,从字符串的最左边开始匹配,每次试图不读入字符匹配,匹配成功,则完成匹配,否则读入一个字符再匹配,依此循环(读入字符、匹配)直到匹配成功或者把字符串的字符匹配完为止。
使用懒惰量词就是在贪婪量词后面中加?,对于之前的例子,他会匹配成51 35 84 54 56
拓展
零宽断言
零宽断言用于查找在某些内容(但并不包括这些内容)之前或之后的东西,也就是说它们像\b,^,$那样用于指定一个位置,这个位置应该满足一定的条件(即断言),因此它们也被称为零宽断言。最好还是拿例子来说明吧: 断言用来声明一个应该为真的事实。正则表达式中只有当断言为真时才会继续进行匹配。
非常抽象而且笼统,对吧,事实上我也那么觉得,以上内容来自百度百科,因为我实在是很难解释这个东西,你可以理解为匹配不含正则结果的内容吧。
正向先行断言(正前瞻)
正前瞻的语法为:
//pattern为正则式
(?=pattern)
它用于匹配pattern表达式之前的内容,并不返回本身。感觉还是很奇怪对吧,举一个例子:今年我市GDP为5600亿元。假设你要将这句话中的5600取出来,你使用正前瞻的方式应该怎么做?
\d+(?=亿元)
正向后行断言(正后顾):
正后顾的语法为:
//pattern为正则式
(?<=pattern)
与正前瞻相反,他是返回pattern之后的内容,如果继续实现之前的内容,那么表达式就会变成
(<=今年我市GDP为)\d+
负向先行断言(负前瞻)
负前瞻的语法为:
//pattern为正则式
(?!pattern)
匹配非pattern表达式的前面内容,不返回本身。还是举之前的例子,我要找到5600亿元之前的字母,那么可以是
[A-Z]+(?!5600亿元)
负向后行断言(负后顾)
这个想必我不需要进行讲解各位也应当能思考出如何书写及使用了,他的语法类似的是:
//pattern为正则式
(?<!pattern)
作用当然是匹配非pattern之后的内容。
我在这里就举这几个例子,还有一些很好的使用手册你可以参考Microsoft Documents。
捕获与非捕获
捕获你可以理解为将表达式按组分配,例如你匹配一个电话010-8511561,010是区号,我们有可能利用正则式将它单独取出来。
数字编号捕获组
语法就是我们之前的分组,但是匹配这个电话号码的时候,他的表达式如果是
((\d{3})-(\d{7}))
那么他会分为三组,第一组是完整的电话,第二组是我们的区号,第三组是我们的电话号码。
命名编号捕获组
语法:
(?<name>exp)
这个name就是你自己自定义的,例如之前的我们可以写成
(?<quhao>\d{3})-(?<haoma>\d{7})
这样我们可以通过名称进行访问组内数据,具体的使用我会在后面进行讲解。
非捕获组
同之前相反,它用于表示不需要分组的数据
(?:exp)
例如我们不需要区号,那么正则式就变成了
(?:\d{3})-(\d{7})
反向引用
捕获会返回一个捕获组,这个分组是保存在内存中,不仅可以在正则表达式外部通过程序进行引用,也可以在正则表达式内部进行引用,这种引用方式就是反向引用。
同样的,根据捕获组命名规则,反向引用也有两种
1- 数字反向引用:\k或\number
2- 命名反向引用:\k或'name'
反向引用通常和捕获组是一同使用的,它的作用主要是用来查找一些重复的内容或者做替换指定字符。比如要查找一串字母"aabbbbgbddesddfiid"里成对的字母。
我们捋捋思路:
- 首先我们要有一个匹配字母的捕获组:(\w)
- 然后(\w)\1
这样就可以了,\1代表的是1分组,这样就是一个匹配成对字母的正则式了。
如何使用正则表达式
位于 System.Text.RegularExpressions 空间下的 Regex 可以对正则表达式进行处理。
Match
这是匹配结果的对象,内含这几个常用的属性及方法
- Value:匹配值
- Groups:分组
- Index:匹配值的第一个字符的索引
- Success:是否符合正则式
- NextMatch:下一个符合的匹配值
Regex.Matches
匹配多个符合的结果,返回一个MatchCollection数组,使用foreach并转换成Match对象进行访问.
- IsMatch:是否符合正则式
- Replace:替换匹配上正则式的字符串
- Split:按匹配上的字符串进行分割
- Match:返回第一个符合正则式的字符串
- Matches:返回所有符合的字符串
您的资助是我最大的动力!
金额随意,欢迎来赏!