正则表达式是记录文本规则的代码,常用于文本匹配、文本替换及输入验证。正则表达式由两种基本字符类型组成:原义(正常)文本字符和元字符,然而,元字符是针对单个字符匹配的,要想要同时匹配多个字符的话,还需要借助限定符;下面介绍一些常见的元字符、限定符以及相关概念。
基本概念
1、常见元字符及限定符
元字符 | 说明 |
---|---|
. | 匹配除 \n 以外的任何字符(注意元字符是小数点) |
[abcde] | 匹配 abcde 之中的任意一个字符 |
[a-h] | 匹配 a 到 h 之间的任意一个字符 |
[^fgh] | 不与 fgh 之中的任意一个字符匹配 |
\w | 匹配大小写英文字符及数字 0 到 9 之间的任意一个及下划线,相当于 [a-zA-Z0-9_] |
\W | 不匹配大小写英文字符及数字 0 到 9 之间的任意一个,相当于 [^a-zA-Z0-9_] |
\s | 匹配任何空白字符,相当于 [ \f\n\r\t\v] |
\S | 匹配任何非空白字符,相当于 [^\s] |
\d | 匹配任何 0 到 9 之间的单个数字,相当于 [0-9] |
\D | 不匹配任何 0 到 9 之间的单个数字,相当于 [^0-9] |
[\u4e00-\u9fa5] | 匹配任意单个汉字(这里用的是 Unicode 编码表示汉字的 ) |
限定符 | 说明 |
---|---|
* | 匹配 0 到多个元字符,相当于 {0,} |
? | 匹配 0 到 1 个元字符,相当于 {0,1} |
{n} | 匹配 n 个元字符 |
{n,} | 匹配至少 n 个元字符 |
{n,m} | 匹配 n 到 m 个元字符 |
+ | 匹配至少 1 个元字符,相当于 {1,} |
\b | 匹配单词边界 |
^ | 字符串必须以指定的字符开始 |
$ | 字符串必须以指定的字符结束 |
1、由于在正则表达式中“ \ ”、“ ? ”、“ * ”、“ ^ ”、“ $ ”、“ + ”、“(”、“)”、“ | ”、“ { ”、“ [ ”等字符已经具有一定特殊意义,如果需要用它们的原始意义,则应该对它进行转义,例如希望在字符串中至少有一个“ \ ”,那么正则表达式应该这么写: \\+ ;
2、可以将多个元字符或者原义文本字符用括号括起来形成一个分组,比如 ^(13)[4-9]\d{8}$ 表示任意以 13开头的移动手机号码;
3、另外对于中文字符的匹配是采用其对应的 Unicode 编码来匹配的,对于单个 Unicode 字符,如 \u4e00 表示汉字“一”, \u9fa5 表示汉字“龥”,在 Unicode 编码中这分别是所能表示的汉字的第一个和最后一个的 Unicode 编码,在 Unicode 编码中能表示 20901 个汉字;
4、关于 \b 的用法,它代表单词的开始或者结尾,以字符串“ 123a 345b 456 789d ”作为示例字符串,如果正则表达式是“ \b\d{3}\b ”,则仅能匹配 456 ;
5、可以使用“ | ”来表示或的关系,例如 [z|j|q] 表示匹配 z 、 j 、 q 之中的任意一个字母。
2、分支
正则表达式里的分支条件指的是有几种规则,如果满足其中任意一种规则都会被匹配到,具体的方法就是用 | 把不同的规则分隔开。
下面以匹配不同区位电话号码为例,剖析一下分支的用法:
0\d{2}-\d{8}|0\d{3}-\d{7}这个表达式能匹配两种以连字号分隔的电话号码:一种是三位区号,8位本地号(如010-12345678),一种是4位区号,7位本地号(0376-2233445)。
3、分组
如果重复单个字符,直接在字符后面加上限定符就行了;但如果想要重复多个字符又该怎么办?你可以用小括号来指定子表达式(也叫做分组),然后你就可以指定这个子表达式的重复次数了。
下面以匹配IP地址为例,剖析一下分组的用法:
((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)这个表达式中,((2[0-4]\d|25[0-5]|[01]?\d\d?)\.)匹配到小于255的正确数字,在这个子表达式 (分组)后面加上{3},表示将这个分组重复3次,最后再加上一个1到3位数字的分组,就能匹配到正确的IP地址了。
4、后向引用
使用小括号进行分组之后,匹配到的分组(子表达式),可以在表达式或其他程序中作进一步的处理。默认情况下,每个分组会自动拥有一个组号,规则是:从左向右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推。后向引用是用于重复搜索前面某个分组匹配的文本,例如,\1代表分组1匹配的文本。
\b(\w+)\b\s+\1\b可以用来匹配重复的单词,像go go, 或者kitty kitty。这个表达式首先是一个单词,也就是单词开始处和结束处之间的多于一个的字母或数字(\b(\w+)\b),这个单词会被捕获到编号为1的分组中,然后是1个或几个空白符(\s+),最后是分组1中捕获的内容(也就是前面匹配的那个单词)(\1)。
5、零宽断言
在前面的元字符介绍中,我们已经知道了有这样一类字符,可以匹配一句话的开始(^)、结束($)或者匹配一个单词的开始、结束(\b)。这些元字符只匹配一个位置,指定这个位置满足一定的条件,而不是匹配某些字符,因此,它们被成为 零宽断言。所谓零宽,指的是它们不与任何字符相匹配,而匹配一个位置;所谓断言,指的是一个判断。正则表达式中只有当断言为真时才会继续进行匹配。
在有些时候,我们精确的匹配一个位置,而不仅仅是句子或者单词,这就需要我们自己写出断言来进行匹配。下面是断言的语法:
限定符 | 说明 |
---|---|
(?=pattern) | 前向肯定断言,匹配pattern前面的位置 |
(?!pattern) | 前向否定断言,匹配后面不是pattern的位置 |
(?<=pattern) | 后向肯定断言,匹配pattern后面的位置 |
(?<!pattern) | 后向否定断言,匹配前面不是pattern的位置 |
1、前向肯定断言示例:比如\b\w+(?=ing\b),匹配以ing结尾的单词的前面部分(除了ing以外的部分),如查找I‘m singing while you‘re dancing.时,它会匹配sing和danc;
2、后向肯定断言示例:比如(?<=\bre)\w+\b会匹配以re开头的单词的后半部分(除了re以外的部分),例如在查找reading a book时,它匹配ading;
3、前向否定断言示例:例如:\d{3}(?!\d)匹配三位数字,而且这三位数字的后面不能是数字;\b((?!abc)\w)+\b匹配不包含连续字符串abc的单词;
4、后向否定断言示例:(?<![a-z])\d{7}匹配前面不是小写字母的七位数字。
6、贪婪与懒惰
当正则表达式中包含能接受重复的限定符时,通常的行为是(在使整个表达式能得到匹配的前提下)匹配尽可能多的字符。以这个表达式为例:a.*b,它将会匹配最长的以a开始,以b结束的字符串。如果用它来搜索aabab的话,它会匹配整个字符串aabab。这被称为贪婪匹配。
有时,我们更需要懒惰匹配,也就是匹配尽可能少的字符。前面给出的限定符都可以被转化为懒惰匹配模式,只要在它后面加上一个问号?。这样.*?就意味着匹配任意数量的重复,但是在能使整个匹配成功的前提下使用最少的重复。例如,a.*?b匹配最短的,以a开始,以b结束的字符串。如果把它应用于aabab的话,它会匹配aab(第一到第三个字符)和ab(第四到第五个字符)。
懒惰限定符 | 说明 |
---|---|
*? | 重复任意次,但尽可能少重复 |
+? | 重复1次或更多次,但尽可能少重复 |
?? | 重复0次或1次,但尽可能少重复 |
{n,m}? | 重复n到m次,但尽可能少重复 |
{n,}? | 重复n次以上,但尽可能少重复 |
Regex类
在C#中由Regex类,采用正则表达式实现字符串的匹配、提取、分割、替换。
1、字符串匹配
方法 | IsMatch() |
格式 | Regex.IsMatch("字符串", "正则表达式") |
作用 | 判断字符串是否符合模板要求 |
返回值 | bool类型,代表是否匹配成功 |
2、字符串提取
方法 | 单次匹配Match()、 多次匹配Matches() |
格式 | Match match = Regex.Match("字符串", "正则表达式") MatchCollection matches= Regex. Matches ("字符串", "正则表达式") |
作用 | 1、提取匹配的子字符串 2、提取组。Groups的下标由1开始,0中存放match的value |
返回值 | Match类型、MatchCollection类型 |
3、字符串分割
方法 | Split() |
格式 | Regex.Split("字符串", "正则表达式") |
作用 | 根据条件分割字符串 |
返回值 | 字符串数组,string[] |
4、字符串替换
方法 | Replace() |
格式 | Regex.Replace("字符串", "正则表达式",“替换字符串”) |
作用 | 在指定字符串内,使用指定字符串替换正则表达式匹配到的地方 |
返回值 | string类型,替换之后的字符串 |
常用大全
说明 | 格式 |
---|---|
匹配中文字符 | [\u4e00-\u9fa5] |
匹配网址URL | [a-zA-z]+://[^\s]* |
匹配Email地址 | \w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)* |
匹配国内电话号码 | \d{3}-\d{8}|\d{4}-\d{7} |
匹配国内手机号码 | (86)*0*13\d{9} |
匹配身份证号码 | \d{15}|\d{18} |
匹配IP地址 | ((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?) |
匹配日期 | ^[1-9]\d{3}([-|\/|\.])?((0\d)|([1-9])|(1[0-2]))\1(([0|1|2]\d)|([1-9])|3[0-1])$ |
匹配HTML标签 | <Title>.*?</Title> |
匹配HTML标签内容 | (?<=<Title>).*?(?=</Title>) |