正则表达式介绍

什么是正则表达式?

Regular Expression,是计算机科学的一个重要概念,它使用一种数学算法来解决计算机程序中的文本检索、匹配等问题,正则表达式语言是一种专门用于字符串处理的语言。在很多语言中都提供了对它的支持。C#也不例外,它可以帮我们解决下面的问题:

  1. 检索:通过正则表达式,从字符串中获取我们想要的部分
  2. 匹配:判断给定的字符串是否符合正则表达式的过滤逻辑

正则表达式表述了一个字符串的书写规则,可以用来判断用户输入的密码和邮箱是否合法。

正则表达式的组成

正则表达式就是由普通字符以及特殊字符(称为元字符)组成的文字模式。该模式描述在查找文字主体时待匹配的一个或多个字符串。

常用正则表达式的方法和委托

在C#中的正则表达式方法位于System.Text.RegularExpressions中,下面介绍其中的Regex类的一些静态方法和委托

静态方法IsMatch

静态方法IsMatch:返回值bool,用于判断指定的字符串是否与正则表达式字符串匹配,它有三个重载方法。

1
bool IsMatch(string input,string pattern);

参数: input:要搜索匹配项的字符串。

	 pattern:要匹配的正则表达式模式。

	 返回结果:如果正则表达式找到匹配项,则为true,否则为false。

1
bool IsMatch(string input,string pattern,RegexOptions options);

参数: input:要搜索匹配项的字符串。

	 pattern:要匹配的正则表达式模式。

	 options: 枚举值的一个按位组合,这些枚举值提供匹配选项。

	 返回结果:如果正则表达式找到匹配项,则为true,否则为false。

1
bool IsMatch(string input,string pattern,RegexOptions options,TimeSpan matchTimeout);

参数: input:要搜索匹配项的字符串。

	 pattern:要匹配的正则表达式模式。

	 options: 枚举值的一个按位组合,这些枚举值提供匹配选项。

	 matchTimeout: 超时间隔,或System.Text.RegularExpressions.Regex.InfiniteMathTimeout指示该方法不应超时

	 返回结果:如果正则表达式找到匹配项,则为true,否则为false。

关于参数RegexOptions

它是一个枚举类型,有一下枚举值

RegexOptions枚举值 内联标志 简单说明
ExplicitCapture n 只有定义了命名或编号的组才能捕获
IgnoreCase i 不区分大小写
IgnorePatternWhiteSpace x 消除模式中的非转义空白并启用由#标记的注释
MultiLine m 多行模式,其原理是修改了^和$的含义
SingleLine s 单行模式,和MultiLine相对应

内联标志可以更小力度(一组为单位)的定义匹配选项

静态方法Match

静态方法Match,使用指定的匹配选项在输入字符串中搜索指定的正则表达式的第一个匹配项。返回一个包含有关匹配信息的对象。同样有三个重载方法,参数和IsMatch方法相同。此外,在Regex类中,还有一个同名的非静态方法,适用于多个实例的情况下,效率更高一些。

1
2
3
Match Match(string input,string pattern);
Match Match(string input,string pattern,RegexOptions options);
Match Match(string input,string pattern,RegexOptions options,TimeSpan matchTimeout);

静态方法Matches

静态方法Matches,使用指定的匹配选项在输入字符串中搜索指定的正则表达式的所有匹配项。跟上面方法有不同之处,就是这个方法返回的是所有的匹配项,他同样有三个重载方法,并且参数和Match方法完全相同

1
2
3
MatchCollection Matches(string input,string pattern);
MatchCollection Matches(string input,string pattern,RegexOptions options);
MatchCollection Matches(string input,string pattern,RegexOptions options,TimeSpan matchTimeout);

Replaces函数

正则表达式主要是验证,提取,分割,替换字符的功能,Replace函数是实现替换功能的。

1
2
3
4
Replace(string input,string pattern,string repalcement);
//input是源字符串,pattern是匹配的条件,replacement是替换的内容,就是把匹配条件pattern的内容转换成replacement的内容。
//比如string result = Regex.Replace("abc","ab","##");
//结果是##c
1
2
3
4
Replace(string input,string pattern,string repalcement,RegexOptions options);
//RegexOptions 是一个枚举类型,用来做一些设定
//前面解释过RegexOptions枚举的内容,如果在匹配时忽略大小写就可以用RegexOptions.IgnoreCase
//比如string result = Regex.Replace("ABc","ab","##",RegexOptions.IgnoreCase);

如果是简单的替换用上面的两个函数就可以实现了,但如果有些复杂的替换,比如匹配到很多内容,不同的内容要替换成不同的字符,就需要用到下面两个函数。

1
2
Replace(string input,string pattern,MatchEvaluator evaluator);
//evaluator是一个代理,其实简单的说是一个函数指针,把一个函数作为参数
1
2
Replace(string input,string pattern,MatchEvaluator evaluator,RegexOptions options);
//和上面功能一样,添加了RegexOptions参数

静态方法Split

使用正则表达式匹配的位置,将文本拆分为一个字符串数组,同样有三个重载方法,返回值为字符串数组。

1
2
3
string[] Split(string input,string pattern);
string[] Split(string input,string pattern,RegexOptions options);
string[] Split(string input,string pattern,RegexOptions options,TimeSpan matchTimeout);

“@”符号

我们经常在正则表达式字符串前面加上“@”字符,这样不让编译器去解析其中的转义字符,而作为正则表达式的语法(元字符)存在。

定位元字符

正则表达式中的元字符有多种,其中用于定位的字符称为定位元字符

元字符 说明
\b 匹配单词的开始或结束
\B 匹配非单词的开始或结束
^ 匹配必须出现在字符串的开头或行的开头
$ 匹配必须出现在以下位置:字符串结尾、字符串结尾处的\n之前或行的结尾
\A 指定匹配必须出现在字符串的开头(忽略Multiline选项)
\Z 指定匹配必须出现在字符串的结尾(忽略Multiline选项)
\z 指定匹配必须出现在字符串的结尾或字符串结尾处的\n之前(忽略Multiline选项)
\G 指定匹配必须出现在上一个匹配结束的地方。与Match.NextMatch()一起使用时,此断言确保所有匹配都是连续的

定位元字符示例

1
2
3
4
5
6
7
8
9
10
static void Main(string[] args)
{
string s = "I am blue cat";
Console.WriteLine(Regex.Replace(s,"^","开始:"));
string ss = "I am blue dog";
Console.WriteLine(Regex.Replace(ss,"$","结束"));
}
//output:
//开始;I am blue cat
//I am blue dog结束

基本语法元字符

字符 说明
. 匹配除换行符以外的任意字符,如果专门匹配“.”就用“\.”
\w 匹配字母、数字、下划线、汉字(指大小写字母、0-9数字、下划线”_“)
\W \w的补集(除“大小写字母、0-9数字、下划线”_“” 之外)
\s 匹配任意空白符(包括换行符\n、回车符\r、制表符\t、垂直制表符\v、换页符\f)
\S \s的补集(除\s定义的字符之外)
\d 匹配数字(0-9数字)
\D 表示\d的补集(除0-9数字之外)

基本语法元字符练习

校检只允许输入数字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
using System;
using System.Text.RegularExpressions;

namespace 正则表达式
{
class Program
{
static void Main(string[] args)
{
string s = Console.ReadLine();
/*^ 匹配必须出现在字符串的开头或行的开头
*\d 匹配数字(0-9数字)
* * 是元字符,表示一个或多个(有一个或多个\d)
* $ 匹配必须出现在以下位置:字符串结尾、字符串结尾处的 \n 之前或行的结尾。
* (表示以\d数字结尾)
*/
string pattern = @"^\d*$";
bool a = Regex.IsMatch(s, pattern);
Console.WriteLine(a);
}
}
}
//test:
//123456789
//True
//
//123456dw2
//False

反义字符

字符 说明
\W \w的补集(除“大小写字母、0-9数字、下划线”_“” 之外)
\S \s的补集(除\s定义的字符之外)
\D 表示\d的补集(除0-9数字之外)
\B 匹配非单词的开始或结束
[ab] 匹配括号中的字符
[a-c] 匹配a到c的字符
[^x] 匹配除了x以外的任意字符
[^adwz] 匹配除了adwz这个几个字符以外的任意字符

反义字符示例:

1
2
3
4
5
6
string strFind1 = "I am a Cat!",strFind2 = "My Name's Bule cat!";
Console.WriteLine("除ahou之外的所有字符,原字符为:" + strFind1 + "替换后:" + Regex.Replace(strFind1,@"[^ahou]","*"));
Console.WriteLine("除ahou之外的所有字符,原字符为:" + strFind2 + "替换后:" + Regex.Replace(strFind2,@"[^ahou]","*"));

//output:
//* a* a *a**

重复描述字符

字符 说明
{n} 匹配前面的字符n次
{n,} 匹配前面的字符n次或多于n次
{n,m} 匹配前面的字符n到m次
? 前面重复零次或一次
+ 前面重复一次或更多次
* 前面重复零次或更多次

重复描述字符示例

校检输入内容为合法QQ号(备注:QQ号为5-12位数字)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
static void Main(string[] args)
{
string qq1 = "2345567";
string qq1 = "23456723456789";
string qq1 = "d2345672";
string qq1 = "234dfg234";

string pattern = @"^\d{6,12}$";//如果不加^,则字符串的子字符串符合要求也能返回True
Console.WriteLine(Regex.IsMatch(qq1,pattern));
Console.WriteLine(Regex.IsMatch(qq2,pattern));
Console.WriteLine(Regex.IsMatch(qq3,pattern));
Console.WriteLine(Regex.IsMatch(qq4,pattern));

}
//output:
//True
//False
//False
//False

择一匹配符

字符 说明
| 将两个匹配条件进行逻辑“或”(Or)运算

择一匹配符示例一

查找数字或字母

1
2
3
4
5
6
7
8
9
10
11
string findStr1 = "ad(d3)-df";
string regexFindStr = @"[a-z]|\d";
string newStrFind = String.Empty;
MatchCollection newStr = Regex.Matches(findStr1,regexFindStr);
newStr.Cast<Match>().Select(m => m.Value).ToList<string>().ForEach(i => newStrFind += i);
//使用Linq,
//IEnumerable<TResult> Cast<TResult> (this IEnumerable source); 首先将MatchCollection类型转换为Match类型
//IEnumerable<TResult> Select<TSource,TResult> (this IEnumerable<TSource> source, Func<TSource,TResult> selector); 将Match类型转化为Match.Value内部的类型
//List<TSource> ToList<TSource> (this IEnumerable<TSource> source); 将IEnumerable转化为List,为的是能使用ForEach方法,这个是List中才有的方法。
//void ForEach (Action<T> action); 对List中的每一个元素都执行操作
Console.WriteLine(findStr1 + "中的字母和数字组成的新字符串为:" + newStrFind);

择一匹配符示例二

将人名输出(”zhangsan;lisi,wangwu.zhaoliu”)

1
2
3
string strSplit = "zhangsan;lisi,wangwu.zhaoliu";
string regexSplitstr = @"[;]|[,]|[.]";
Regex.Split(strSplit,regexSplitstr).ToList().ForEach(i => Console.WriteLine(i));

对正则表达式进行分组

小括号来指定子表达式(也叫做分组)

示例一:重复单字符 和 重复分组字符

1
2
3
4
5
6
7
8
9
10
Console.WriteLine("请输入一个任意字符串,测试分组:");
string inputStr = Console.ReadLine();
string strGroup1 = @"a{2}";
string outputStr = Regex.Replace(inputStr,strGroup1,"22");
Console.WriteLine("单字符重复a两次替换为22,结果为:" + outputStr);

//重复 多个字符 使用(abcd){n}进行分组限定
string strGroup2 = @"(ab\w{2}){2}";
string outputStr2 = Regex.Replace(inputStr,strGroup2,"5555");
Console.WriteLine("分组字符重复ab--两次替换为5555,结果为:" + outputStr2);

示例二:校检IP4地址

例如:192.168.1.4,为4段,每段最多三位,每段最大数字255,并且第一位不能为0

1
2
3
4
5
6
7
8
9
string regexStrIP4 = @"^(((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:200~249
//25[0-5]:250~255
//[01]?\d\d?:0~199 如何保证第一位不能为0?存疑?
//\.:匹配.
Console.WriteLine("请输入一个IP4地址:");
string inputStrIP4 = Console.ReadLine();
bool isMatch = Regex.IsMatch(inputStrIP4,regexStrIP4);
Console.WriteLine("是否为合法地址:" + isMatch);