在 C# 的编程世界中,正则表达式是一个强大且实用的工具,它能帮助开发者高效地处理文本检索和匹配等复杂问题。本文将详细介绍正则表达式的概念、组成,以及 C#中 ——System.Text.RegularExpressions 命名空间下 Regex 类的使用。
一、正则表达式概述
正则表达式,英文名为 Regular Expression,是计算机科学领域的重要概念。它借助数学算法,解决计算机程序里的文本检索、匹配等难题。正则表达式语言专注于字符串处理,在众多编程语言中都得到了广泛支持,C# 也不例外。
- 检索:通过正则表达式,从字符串中精准获取所需部分。
- 匹配:判断给定字符串是否符合正则表达式设定的过滤逻辑。
可以将正则表达式理解为定义字符串书写规则的工具,比如判断用户输入的密码是否合法,或者邮箱格式是否正确。
二、正则表达式的组成
正则表达式由普通字符和特殊字符(即元字符)构成文字模式,该模式描述了在查找文字主体时待匹配的一个或多个字符串。
三、C# 中操作正则表达式
在 C# 中,System.Text.RegularExpressions
命名空间下的 Regex
类提供了一系列静态方法和委托,用于操作正则表达式。
1. IsMatch
静态方法
该方法用于判断指定字符串是否与正则表达式匹配,返回值为布尔类型,有三个重载方法:
bool IsMatch(string input, string pattern);
- 参数:
input
:要搜索匹配项的字符串。pattern
:要匹配的正则表达式模式。
- 返回结果:如果正则表达式找到匹配项,则返回
true
;否则,返回false
。
bool IsMatch(string input, string pattern, RegexOptions options);
- 参数:
input
:要搜索匹配项的字符串。pattern
:要匹配的正则表达式模式。options
:枚举值的按位组合,提供匹配选项。
- 返回结果:如果正则表达式找到匹配项,则返回
true
;否则,返回false
。
bool IsMatch(string input, string pattern, RegexOptions options, TimeSpan matchTimeout);
- 参数:
input
:要搜索匹配项的字符串。pattern
:要匹配的正则表达式模式。options
:枚举值的按位组合,提供匹配选项。matchTimeout
:超时间隔,或System.Text.RegularExpressions.Regex.InfiniteMatchTimeout
指示该方法不应超时。
- 返回结果:如果正则表达式找到匹配项,则返回
true
;否则,返回false
。
2.RegexOptions
枚举类型
RegexOptions
是一个枚举类型,包含以下常用枚举值:
RegexOptions 枚举值 | 内联标志 | 简单说明 |
---|---|---|
ExplicitCapture | n | 只有定义了命名或编号的组才捕获 |
IgnoreCase | i | 不区分大小写 |
IgnorePatternWhitespace | x | 消除模式中的非转义空白并启用由 # 标记的注释 |
MultiLine | m | 多行模式,修改了 ^ 和 $ 的含义 |
SingleLine | s | 单行模式,与 MultiLine 相对应 |
内联标志可针对一组正则表达式,更精细地定义匹配选项。
3. Match
静态方法
该方法使用指定的匹配选项,在输入字符串中搜索指定正则表达式的第一个匹配项,返回一个包含匹配信息的对象。同样有三个重载方法,参数与 IsMatch
方法相同:
Match Match(string input, string pattern);
Match Match(string input, string pattern, RegexOptions options);
Match Match(string input, string pattern, RegexOptions options, TimeSpan matchTimeout);
此外,Regex
类中还有一个同名的非静态方法,在处理多个实例时,效率更高。
3. Matches
静态方法
该方法在指定的输入字符串中搜索指定正则表达式的所有匹配项,与 Match
方法不同,它返回所有匹配项。同样有三个重载方法,参数与 Match
方法完全相同:
MatchCollection Matches(string input, string pattern);
MatchCollection Matches(string input, string pattern, RegexOptions options);
MatchCollection Matches(string input, string pattern, RegexOptions options, TimeSpan matchTimeout);
4. Replace
方法
正则表达式主要用于验证、提取、分割和替换字符串,Replace
方法实现了替换功能,有以下四个重载方法:
string Replace(string input, string pattern, string replacement);
- 参数:
input
:源字符串。pattern
:匹配条件。replacement
:替换内容,将符合匹配条件pattern
的内容替换为此内容。
string result = Regex.Replace("abc", "ab", "##");
// 结果是##c,把字符串abc中的ab替换成##
string Replace(string input, string pattern, string replacement, RegexOptions options);
- 参数:
input
:源字符串。pattern
:匹配条件。replacement
:替换内容。options
:RegexOptions
枚举类型,用于设定匹配选项,如忽略大小写可使用RegexOptions.IgnoreCase
。
string result = Regex.Replace("ABc", "ab", "##", RegexOptions.IgnoreCase);
对于复杂的替换需求,比如匹配到多种内容,需要将不同内容替换成不同字符,可使用以下两个方法:
string Replace(string input, string pattern, MatchEvaluator evaluator);
- 参数:
input
:源字符串。pattern
:匹配条件。evaluator
:一个代理,本质上可理解为一个函数指针,通过代理绑定的函数实现复杂替换。
string Replace(string input, string pattern, MatchEvaluator evaluator, RegexOptions options);
- 参数:
input
:源字符串。pattern
:匹配条件。evaluator
:一个代理。options
:RegexOptions
枚举类型,用于设定匹配选项。
5. Split
静态方法
该方法使用正则表达式匹配的位置,将文本拆分为一个字符串数组,有三个重载方法:
string[] Split(string input, string pattern);
string[] Split(string input, string pattern, RegexOptions options);
string[] Split(string input, string pattern, RegexOptions options, TimeSpan matchTimeout);
四、正则表达式中的特殊符号与示例
1. @
符号
在正则表达式字符串前加上 @
字符,可防止编译器解析其中的转义字符,使其作为正则表达式的语法(元字符)存在。
string s = @"www.baidu.com \n lkjsdflkj";
2. 定位元字符
字符 | 说明 |
---|---|
\b | 匹配单词的开始或结束 |
\B | 匹配非单词的开始或结束 |
^ | 匹配必须出现在字符串的开头或行的开头 |
$ | 匹配必须出现在以下位置:字符串结尾、字符串结尾处的 \n 之前或行的结尾 |
\A | 指定匹配必须出现在字符串的开头(忽略 Multiline 选项) |
\z | 指定匹配必须出现在字符串的结尾(忽略 Multiline 选项) |
\z | 指定匹配必须出现在字符串的结尾或字符串结尾处的 \n 之前(忽略 Multiline 选项) |
\G | 指定匹配必须出现在上一个匹配结束的地方,与 Match.NextMatch() 一起使用时,确保所有匹配都是连续的 |
定位元字符示例
// 示例一:匹配开始 ^
string str = "I am Blue cat";
Console.WriteLine(Regex.Replace(str, "^", "准备开始:"));
// 示例二:匹配结束 $
string str2 = "I am Blue cat";
Console.WriteLine(Regex.Replace(str2, "$", " 结束了!"));
3. 基本语法元字符
字符 | 说明 |
---|---|
. | 匹配除换行符以外的任意字符 |
\w | 匹配字母、数字、下划线、汉字 (指大小写字母、0 - 9 的数字、下划线_) |
\W | \w 的补集 (除 “大小写字母、0 - 9 的数字、下划线_” 之外) |
\s | 匹配任意空白符 (包括换行符 \n 、回车符 \r 、制表符 \t 、垂直制表符 \v 、换页符 \f ) |
\S | \s 的补集 (除 \s 定义的字符之外) |
\d | 匹配数字 (0 - 9 数字) |
\D | 表示 \d 的补集 (除 0 - 9 数字之外) |
在正则表达式中,\
是转义字符,*
是元字符。若要表示 \
、.
、*
字符,需使用 \\
、\.
、\*
。
基本语法元字符示例
// 示例一:校验只允许输入数字
string strCheckNum1 = "23423423a3", strCheckNum2 = "324234";
Console.WriteLine("匹配字符串" + strCheckNum1 + "是否为数字:" + Regex.IsMatch(strCheckNum1, @"^\d*$"));
Console.WriteLine("匹配字符串" + strCheckNum2 + "是否为数字:" + Regex.IsMatch(strCheckNum2, @"^\d*$"));
// 示例二:校验只允许输入除大小写字母、0 - 9的数字、下划线_以外的任何字符
string strCheckStr1 = "abcds_a", strCheckStr2 = "**&&((((2", strCheckStr3 = "**&&((((";
string regexStr = @"^\W*$";
Console.WriteLine("匹配字符串" + strCheckStr1 + "是否为除大小写字母、0 - 9的数字、下划线_以外的任何字符:" + Regex.IsMatch(strCheckStr1, regexStr));
Console.WriteLine("匹配字符串" + strCheckStr2 + "是否为除大小写字母、0 - 9的数字、下划线_以外的任何字符:" + Regex.IsMatch(strCheckStr2, regexStr));
Console.WriteLine("匹配字符串" + strCheckStr3 + "是否为除大小写字母、0 - 9的数字、下划线_以外的任何字符:" + Regex.IsMatch(strCheckStr3, regexStr));
4. 反义字符
字符 | 说明 |
---|---|
\W | \w 的补集 (除 “大小写字母、0 - 9 的数字、下划线_” 之外) |
\S | \s 的补集 (除 \s 定义的字符之外) |
\D | 表示 \d 的补集 (除 0 - 9 数字之外) |
\B | 匹配不是单词开头或结束的位置 |
[ab] | 匹配中括号中的字符 |
[a - c] | 匹配 a 字符到 c 字符之间的字符 |
[^x] | 匹配除了 x 以外的任意字符 |
[^adwz] | 匹配除了 adwz 这几个字符以外的任意字符 |
反义字符示例
// 示例:查找除ahou这之外的所有字符
string strFind1 = "I am a Cat!", strFind2 = "My Name's Blue cat!";
Console.WriteLine("除ahou这之外的所有字符,原字符为:" + strFind1 + "替换后:" + Regex.Replace(strFind1, @"[^ahou]", "*"));
Console.WriteLine("除ahou这之外的所有字符,原字符为:" + strFind2 + "替换后:" + Regex.Replace(strFind2, @"[^ahou]", "*"));
5. 重复描述字符
字符 | 说明 |
---|---|
{n} | 匹配前面的字符 n 次 |
{n,} | 匹配前面的字符 n 次或多于 n 次 |
{n,m} | 匹配前面的字符 n 到 m 次 |
? | 重复零次或一次 |
+ | 重复一次或更多次 |
* | 重复零次或更多次 |
重复描述字符示例
// 示例:校验输入内容是否为合法QQ号(备注:QQ号为5 - 12位数字)
string isQq1 = "1233", isQq2 = "a1233", isQq3 = "0123456789123", isQq4 = "556878544";
string regexQq = @"^\d{5,12}$";
Console.WriteLine(isQq1 + "是否为合法QQ号(5 - 12位数字):" + Regex.IsMatch(isQq1, regexQq));
Console.WriteLine(isQq2 + "是否为合法QQ号(5 - 12位数字):" + Regex.IsMatch(isQq2, regexQq));
Console.WriteLine(isQq3 + "是否为合法QQ号(5 - 12位数字):" + Regex.IsMatch(isQq3, regexQq));
Console.WriteLine(isQq4 + "是否为合法QQ号(5 - 12位数字):" + Regex.IsMatch(isQq4, regexQq));
6. 择一匹配
|
字符用于将两个匹配条件进行逻辑 “或”(Or)运算。
择一匹配示例
// 示例一:查找数字或字母
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);
Console.WriteLine(findStr1 + "中的字母和数字组成的新字符串为:" + newStrFind);
// 示例二:将人名输出("zhangsan;lisi,wangwu.zhaoliu")
string strSplit = "zhangsan;lisi,wangwu.zhaoliu";
string regexSplitstr = @"[;]|[,]|[.]";
Regex.Split(strSplit, regexSplitstr).ToList().ForEach(i => Console.WriteLine(i));
7. 对正则表达式分组 ()
使用小括号来指定子表达式(也叫做分组)。
分组示例
// 示例一:重复单字符和重复分组字符
Console.WriteLine("请输入一个任意字符串,测试分组:");
string inputStr = Console.ReadLine();
string strGroup1 = @"a{2}";
Console.WriteLine("单字符重复2两次替换为22,结果为:" + Regex.Replace(inputStr, strGroup1, "22"));
// 重复多个字符 使用(abcd){n}进行分组限定
string strGroup2 = @"(ab\w{2}){2}";
Console.WriteLine("分组字符重复2两次替换为5555,结果为:" + Regex.Replace(inputStr, strGroup2, "5555"));
// 示例二:校验IP4地址(如:192.168.1.4,为四段,每段最多三位,每段最大数字为255,并且第一位不能为0)
string regexStrIp4 = @"^(((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?))$";
Console.WriteLine("请输入一个IP4地址:");
string inputStrIp4 = Console.ReadLine();
Console.WriteLine(inputStrIp4 + " 是否为合法的IP4地址:" + Regex.IsMatch(inputStrIp4, regexStrIp4));
Console.WriteLine("请输入一个IP4地址:");
string inputStrIp4Second = Console.ReadLine();
Console.WriteLine(inputStrIp4 + " 是否为合法的IP4地址:" + Regex.IsMatch(inputStrIp4Second, regexStrIp4));
五·结语
通过对正则表达式的深入学习,我们能够在 C# 编程中,更高效地处理字符串相关的复杂问题。