【定义】
正则表达式是一个字符串,以某种句法规则来描述、匹配、检索一般字符串。简单来说,我们可以通过正则表达式来约束用户输入的文本(字符串)、对某一字符串按照我们的期望进行校正或者对某一字符串提取出符合我们要求的子字符串。
举几个简单的例子,比如我们登陆QQ,在账号部分,软件期望我们输入的是QQ号、手机号或者是电子邮箱,而用户输入的可能是一串乱码。当用户输入完之后,软件会对用户输入的账号进行处理。首先就要利用正则表达式来判定这个账号是不是QQ号、手机号与电子邮箱其中的一种,然后再进行匹配。这样做的目的可以大大提高工作效率。
【常用字符】
注1:通常在正则表达式的字符串前加@符号,表示此字符串中的转义符用于正则表达式的规则。
注2:此处只给出了初学常用的部分字符,并非完整版。
字符 | 语义 |
---|---|
\ | 标记下一字符为特殊字符(比如\w),或将特殊字符转义(比如\^就是匹配^,因为其本身有特殊意义) |
^ | 匹配必须出现在字符串的开头位置 |
$ | 匹配必须出现在字符串的结尾或者字符串结尾\n之前 |
. | 匹配除了换行符以外的任意字符 |
\w | 匹配字母(a-z,A-Z)数字(0-9)下划线(_)汉字 |
\W | 匹配\w的补集 |
\s | 匹配任意空白符(换行符\n 回车符/r 制表符/t 垂直制表符/v 换页符/f) |
\S | 匹配\s的补集 |
\d | 匹配数字(0-9) |
\D | 匹配\d的补集 |
[ach] | 匹配中括号间包含的任意一个字符 |
[a-c] | 匹配指定范围内任意一个字符 |
[^x] | 匹配除x以外的任意一个字符 |
[^abcd] | 匹配除abcd以外的任意一个字符 |
[^a-z] | 匹配除指定范围以外的任意一个字符 |
{n} | 非负整数,匹配某一字符连续出现n次,例如p{2}匹配apple中的pp而不匹配aply中的p |
{n,} | 非负整数,匹配某一字符至少出现n次 |
{n,m} | n<=m且m,n均为非负整数,匹配某一字符出现n-m次 |
? | 匹配表达式0次或者1次。其等价于{0,1} |
+ | 匹配表达式1次或者多次。其等价于{1,} |
* | 匹配表达式0次或者多次,其等价于{0,} |
| | 表示逻辑“或”的关系 |
【常用API】
命名空间:System.Text.RegularExpressions
类:Regex
注:此处只给出了部分初学者适用的API函数,并非完整版。
构造函数:
public Regex(string pattern);
描述:
用一个正则表达式作为参数来构造Regex对象。其包含的成员方法与下述静态方法同名,且重载方法要多于静态方法。多数与静态方法大同小异,且静态方法较为常用,所以这里不过多介绍成员方法。有兴趣的读者在学习完静态方法可以自己去查询相关API,比较容易上手。
静态方法:
匹配:
public static bool IsMatch(string input, string pattern);
public static bool IsMatch(string input, string pattern, RegexOptions options);
描述:
input表示待匹配的字符串,pattern表示正则表达式,options是个结构体类型的参数,此参数用于在匹配时根据特定需求进行指定。
该方法返回一个bool值,True表示匹配成功。
示例:
//只能匹配数字串
//原因:此处限定了匹配数字0次或者多次,且开头与结尾均限定为数字,所以必须是纯数字串,
// 如果去掉^和$,则该串含有数字串即可
string pattern = @"^\d*$";
string input1 = "999";
string input2 = "qwfsdf";
string input3 = "9w3423";
//只要有一个满足正则表达式的子字符串就返回true
Console.WriteLine(Regex.IsMatch(input1, pattern));
Console.WriteLine(Regex.IsMatch(input2, pattern));
Console.WriteLine(Regex.IsMatch(input3, pattern));
结果:
True
False
False
分割:
public static string[] Split(string input, string pattern);
public static string[] Split(string input, string pattern, RegexOptions options);
描述:
参数与上述类似,这里的正则表达式表示匹配成功了则被作为分隔符。
该方法返回一个string数组,每一个元素都是被分割出来的子字符串。
示例:
//给定一个包含很多名字和分隔符的字符串
string input = "ZhangSan,LiSi;.";
//匹配字符所包含的分隔符
string pattern = @"[;,.]";
//也可以利用或运算写成下面这种形式
//string pattern = @"[,]|[;]|[.]";
//利用此方法分割后会得到一个字符串数组
string[] names = Regex.Split(input, pattern);
//遍历取值
foreach (string name in names)
{
Console.WriteLine(name);
}
结果:
ZhangSan
LiSi
WangWu
ZhaoLiu
替换:
public static string Replace(string input, string pattern, string replacement);
public static string Replace(string input, string pattern, string replacement, RegexOptions options);
描述:
参数与上述类似,这里的正则表达式表示匹配成功的字符(串)将被替换。参数replacement表示符合规则的字符被替换成replacement。
该方法返回一个string值,返回的是替换后的字符串。
示例:
string input = "What's the f*ck!";
string pattern = @"f*ck";
string replacement = "****";
string resulet = Regex.Replace(input, pattern, replacement);
Console.WriteLine(resulet);
结果:
What's the ****!
筛选:
public static Match Match(string input, string pattern);
public static Match Match(string input, string pattern, RegexOptions options);
public static MatchCollection Matches(string input, string pattern);
public static MatchCollection Matches(string input, string pattern, RegexOptions options);
描述:
参数与上述类似。这里的正则表达式用于匹配需要提取的子字符串。Match方法会提取匹配到的第一个符合正则表达式的字符串,而Matches会提取所有符合条件的字符串并放入MatchCollection类型的集合中,集合中的对象为Match类型。
前者返回一个Match对象,后者返回MatchCollection类型集合(一群Match对象)。
示例:
string input = "34 $#%((( d 是大家 _\n";
//只提取数字和a-z之间的字母
string pattern = @"\d|[a-z]";
MatchCollection matches = Regex.Matches(input, pattern);
foreach (Match result in matches)
{
Console.WriteLine(result.ToString());
}
结果:
3
4
d
【综合练习】
问题描述:
给定一个字符串,判定它是否为IPv4类型的地址。例如输入192.168.1.1,则打印True;输入1.02.888.1,则打印False。
问题分析:
IPv4类型的IP地址以点分十进制形式表示,共四组数字,以“.”分隔,每组数字的范围都在0-255,且不会出现0开头的多位数,如001,09等。
解决思路:
一组数字+一个点我们可以当做一个整体来看,即我们只要写出数字+点组合的正则表达式后,在其后面加上{3}即可以将其重复三次,而最后一组数我们去掉点的正则即可。
有了上述的思路,现在主要解决的是如何匹配0-255的所有数。我们拆分看这个问题。
【200-255】
首先如果是25开头的数,则第三位数的范围是0-5,可以写作25[0-5];如果是2开头,则第二位数是0-4范围,而第三位数是0-9范围,可以写作2[0-4]\d。
【100-199】
此时为1开头,第二位数可以是0-9,第三位数可以是0-9,可以写作1\d\d。
【10-99】
此时第一位数可以是1-9,第二位数可以是0-9,可以写作[1-9]\d。
【0-9】
这里可以直接写作\d。
这里我们可以看到一共有5种情况(200-255的有两种),每一种情况之间我们可以用“|”来进行分隔,表示他们是逻辑或的关系。然后这里我们用小括号对来分组,小括号在前面的字符表里没有介绍,这里简单说一下,小括号用来对正则表达式进行分组,可以将一个组看为一个整体,然后整体的进行操作。最终我们写出的正则表达式如下:
^(((2[0-4]\d|25[0-5]|1\d\d|[1-9]\d|\d)[.]){3}(2[0-4]\d|25[0-5]|1\d\d|[1-9]\d|\d))$
注:
(2[0-4]\d|25[0-5]|1\d\d|[1-9]\d|\d)表示数字位的整体;
((2[0-4]\d|25[0-5]|1\d\d|[1-9]\d|\d)[.])表示数字位+点为一个整体,这样{3}就是对这个整体进行三次重复;
(((2[0-4]\d|25[0-5]|1\d\d|[1-9]\d|\d)[.]){3}(2[0-4]\d|25[0-5]|1\d\d|[1-9]\d|\d))表示整个式子为一个整体,加上^和$符号来限定开头结尾都必须是这个式子,也就是说严格匹配此正则表达式。
测试代码:
示例:
//这里为了便于测试,可以之写出一组数字+点的组合
string ipPattern = @"^((2[0-4]\d|25[0-5]|1\d\d|[1-9]\d|\d)[.])$";
string input1 = "192.";
string input2 = "001.";
string input3 = "666.";
string input4 = "104";
string input5 = "192.192.";
Console.WriteLine(Regex.IsMatch(input1, ipPattern));
Console.WriteLine(Regex.IsMatch(input2, ipPattern));
Console.WriteLine(Regex.IsMatch(input3, ipPattern));
Console.WriteLine(Regex.IsMatch(input4, ipPattern));
Console.WriteLine(Regex.IsMatch(input5, ipPattern));
结果:
True
False
False
False
False
【总结】
一直望而却步的正则表达式,今天看视频和相关的学习资料学习了一下,也不是那么的困难,学一些基础的内容足够应付一些比较常用的字符串判断。希望这篇文章能为对这部分知识不熟悉的入门读者提供帮助。(之前没学懂这个是因为直接看到某度的百科,看蒙圈了= =)
【参考资料】
【1】泰课在线 - 第三季 C#高级编程 - siki
【2】维基百科 - 正则表达式
【GitHub】
https://github.com/Eazey/CSharp/tree/master/RegularExpression