一、使用原理
- 模式匹配机制:
- 在 C# 中,正则表达式通过定义一种模式来描述文本的特征。例如,
\d
表示匹配任意一个数字字符。当使用正则表达式进行匹配时,正则表达式引擎会从输入文本的起始位置开始,逐个字符地将输入文本与模式进行比较。 - 引擎尝试找到一个连续的字符序列,该序列与整个模式完全匹配。如果找到了这样的序列,则匹配成功;否则,匹配失败。
- 在 C# 中,正则表达式通过定义一种模式来描述文本的特征。例如,
- 回溯机制:
- 当正则表达式中存在可选部分(如
a?
表示a
可选出现一次或不出现)或重复部分(如a+
表示a
出现一次或多次)时,可能会出现多种匹配的可能性。在这种情况下,正则表达式引擎会使用回溯机制。 - 例如,对于模式
a(b|c)+
和输入文本abcc
,引擎首先匹配a
,然后遇到(b|c)+
,它会尝试匹配b
,接着匹配第一个c
,然后再次匹配c
。如果后续还有更多文本,并且匹配失败,引擎会回溯到上一个选择点,尝试其他可能的匹配路径,直到找到成功匹配或确定无法匹配为止。
- 当正则表达式中存在可选部分(如
- 捕获组:
- 捕获组是正则表达式中的一个重要概念,它允许你将匹配的一部分文本提取出来。通过将模式的一部分用圆括号
()
括起来,可以定义一个捕获组。 - 例如,对于模式
(\d{3})-(\d{3})-(\d{4})
(用于匹配美国电话号码格式,如123 - 456 - 7890
),有三个捕获组。在匹配成功后,可以通过Match.Groups
属性访问这些捕获组,每个捕获组包含了相应部分的匹配文本。
- 捕获组是正则表达式中的一个重要概念,它允许你将匹配的一部分文本提取出来。通过将模式的一部分用圆括号
- 编译与执行:
- 在 C# 中,当使用
Regex
类进行正则表达式操作时,Regex
类会将正则表达式模式编译成一种内部表示形式,以便更高效地执行匹配操作。 - 如果需要多次使用同一个正则表达式模式,可以使用
Regex.CompileToAssembly
方法将正则表达式编译成程序集,进一步提高性能。这在一些需要频繁进行正则匹配的场景(如文本处理的循环中)非常有用。
- 在 C# 中,当使用
二、应用场景
- 数据验证:
- 邮箱地址验证:确保用户输入的邮箱地址符合正确的格式,例如
user@domain.com
。常见的正则表达式模式为^[a-zA-Z0 - 9_.+-]+@[a-zA-Z0 - 9 -]+\.[a-zA-Z0 - 9-.]+$
。 - 电话号码验证:验证电话号码是否符合特定地区的格式。例如,美国电话号码可以用
^\d{3}-\d{3}-\d{4}$
来验证,其中^\d{3}
表示以三个数字开头,-\d{3}
表示中间是一个短横线和三个数字,-\d{4}$
表示最后是一个短横线和四个数字。
- 邮箱地址验证:确保用户输入的邮箱地址符合正确的格式,例如
- 文本提取:
- 从网页中提取链接:在处理网页内容时,需要提取其中的所有链接。可以使用类似
https?://[^\s/$.?#].[^\s]*
的正则表达式,它能匹配http
或https
开头的链接。 - 从日志文件中提取特定信息:例如,在日志文件中提取时间戳、错误代码等信息。假设日志格式为
[2023 - 01 - 01 12:00:00] INFO - Message
,可以用\[\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}\]
来提取时间戳部分。
- 从网页中提取链接:在处理网页内容时,需要提取其中的所有链接。可以使用类似
- 文本替换:
- 格式化文本:将文本中的日期格式从
MM/dd/yyyy
替换为yyyy - MM - dd
。可以使用正则表达式(\d{2})/(\d{2})/(\d{4})
来匹配原日期格式,并通过替换操作将其转换为新的格式。 - 屏蔽敏感信息:在处理用户数据时,可能需要屏蔽敏感信息,如电话号码中的部分数字。可以用
(\d{3})\d{4}(\d{4})
匹配电话号码,并将中间四位数字替换为****
,得到类似123****5678
的结果。
- 格式化文本:将文本中的日期格式从
- 搜索过滤:
- 在文档中搜索特定模式:在大量的文档中搜索包含特定关键词或模式的段落。例如,在一篇技术文档中搜索所有包含
TODO:
标记的行,使用^TODO:.*
的正则表达式,其中^TODO:
表示以TODO:
开头,.*
表示任意字符(包括换行符)。 - 筛选文件列表:在处理文件系统中的文件列表时,可以使用正则表达式来筛选符合特定命名模式的文件。例如,筛选出所有以
report_
开头,以.txt
结尾的文件,可以用^report_.*\.txt$
。
- 在文档中搜索特定模式:在大量的文档中搜索包含特定关键词或模式的段落。例如,在一篇技术文档中搜索所有包含
- 词法分析:
- 编程语言解析:在编译器或解释器中,正则表达式用于将输入的代码分解成一个个词法单元(token)。例如,在解析 C# 代码时,使用正则表达式来识别关键字(如
if
、else
)、标识符(变量名、函数名)、运算符(如+
、-
)等。 - 标记语言解析:对于标记语言(如 HTML、XML),正则表达式可用于解析标签、属性等。例如,在解析 HTML 时,用
<([a-zA-Z]+)(?:\s+[a-zA - Z0 - 9_-]+="[^"]*")*>
来匹配标签及其属性。
- 编程语言解析:在编译器或解释器中,正则表达式用于将输入的代码分解成一个个词法单元(token)。例如,在解析 C# 代码时,使用正则表达式来识别关键字(如
三、常见正则符号含义
- 字符类:
[abc]
:匹配方括号内的任意一个字符,即a
、b
或c
。例如,[123]
可以匹配1
、2
或3
。[a - z]
:匹配小写字母范围内的任意一个字符。例如,[a - f]
可以匹配a
到f
之间的任意一个小写字母。[^abc]
:匹配除了方括号内字符之外的任意一个字符。例如,[^0 - 9]
可以匹配除数字之外的任意字符。
- 预定义字符类:
\d
:匹配任意一个数字字符,等价于[0 - 9]
。例如,\d{3}
可以匹配三个连续的数字。\D
:匹配任意一个非数字字符,等价于[^0 - 9]
。\w
:匹配任意一个字母、数字或下划线字符,等价于[a - zA - Z0 - 9_]
。例如,\w+
可以匹配一个或多个由字母、数字或下划线组成的单词。\W
:匹配任意一个非字母、数字或下划线字符,等价于[^a - zA - Z0 - 9_]
。\s
:匹配任意一个空白字符(空格、制表符、换行符等),等价于[\f\n\r\t\v]
。例如,\s+
可以匹配一个或多个连续的空白字符。\S
:匹配任意一个非空白字符,等价于[^ \f\n\r\t\v]
。
- 限定符:
*
:匹配前面的元素零次或多次。例如,a*
可以匹配空字符串、a
、aa
、aaa
等。+
:匹配前面的元素一次或多次。例如,a+
可以匹配a
、aa
、aaa
等,但不能匹配空字符串。?
:匹配前面的元素零次或一次。例如,a?
可以匹配空字符串或a
。{n}
:匹配前面的元素恰好n
次。例如,a{3}
只能匹配aaa
。{n,}
:匹配前面的元素至少n
次。例如,a{3,}
可以匹配aaa
、aaaa
、aaaaa
等。{n,m}
:匹配前面的元素至少n
次,最多m
次。例如,a{3,5}
可以匹配aaa
、aaaa
、aaaaa
。
- 分组与捕获:
(pattern)
:将pattern
作为一个分组,用于捕获匹配的文本。例如,对于模式(\d{3})-(\d{3})-(\d{4})
匹配电话号码123 - 456 - 7890
,可以通过Match.Groups[1]
获取第一个\d{3}
匹配的123
,Match.Groups[2]
获取456
,Match.Groups[3]
获取7890
。(?:pattern)
:将pattern
作为一个非捕获分组。它用于分组但不捕获匹配的文本,这样可以避免在Match.Groups
中产生额外的捕获组。例如,(?:a|b)+
匹配a
或b
的一次或多次出现,但不会在Match.Groups
中创建捕获组。
- 边界匹配:
^
:匹配字符串的开头。例如,^Hello
可以匹配以Hello
开头的字符串。$
:匹配字符串的结尾。例如,World$
可以匹配以World
结尾的字符串。\b
:匹配单词边界,即单词与非单词字符的边界。例如,\bHello\b
可以匹配独立的Hello
单词,而不会匹配HelloWorld
中的Hello
。\B
:匹配非单词边界。例如,\BHello\B
可以匹配HelloWorld
中Hello
部分(因为Hello
前后都不是单词边界)。
- 转义字符:
\
:用于转义特殊字符,使它们失去特殊含义,仅表示其字面意思。例如,\.
表示匹配一个点号,因为点号在正则表达式中有特殊含义(匹配任意字符)。同样,\*
表示匹配一个星号。
四、详细案例代码
- 验证邮箱地址
using System;
using System.Text.RegularExpressions;
class Program
{
static void Main()
{
string email = "test.user123@example - domain.com";
string pattern = @"^[a-zA-Z0 - 9_.+-]+@[a-zA-Z0 - 9 -]+\.[a-zA-Z0 - 9-.]+$";
bool isValid = Regex.IsMatch(email, pattern);
Console.WriteLine($"Email {email} is valid: {isValid}");
}
}
解释:
^
表示匹配字符串的开头。[a-zA-Z0 - 9_.+-]+
:匹配一个或多个字母、数字、下划线、点、加号或减号,这是邮箱用户名部分。@
:匹配邮箱地址中的@
符号。[a-zA-Z0 - 9 -]+
:匹配域名部分,由字母、数字和短横线组成。\.
:转义后的点号,匹配实际的点号。[a-zA-Z0 - 9-.]+
:匹配顶级域名部分,由字母、数字、短横线和点号组成。$
:表示匹配字符串的结束。
- 提取 URL 链接
using System;
using System.Text.RegularExpressions;
class Program
{
static void Main()
{
string text = "Check out these links: https://www.example.com, http://another - site.net, ftp://ftp.example.org";
string pattern = @"https?://[^\s/$.?#].[^\s]*";
MatchCollection matches = Regex.Matches(text, pattern);
foreach (Match match in matches)
{
Console.WriteLine(match.Value);
}
}
}
解释:
https?
:?
表示?
前面的s
是可选的,即匹配http
或https
。://
:匹配协议与域名之间的分隔符。[^\s/$.?#]
:匹配一个非空白字符且不是/
、$
、.
、?
、#
的字符,这是域名的起始字符。[^\s]*
:匹配任意数量的非空白字符,用于匹配域名和路径部分。
- 替换文本中的电话号码
using System;
using System.Text.RegularExpressions;
class Program
{
static void Main()
{
string text = "Contact me at 123 - 456 - 7890 or 555 - 123 - 4567";
string pattern = @"\d{3}-\d{3}-\d{4}";
string replacement = "(***)-***-****";
string newText = Regex.Replace(text, pattern, replacement);
Console.WriteLine(newText);
}
}
解释:
\d{3}
:匹配三个连续的数字。-\d{3}
:匹配一个短横线和三个连续的数字。-\d{4}
:匹配一个短横线和四个连续的数字。Regex.Replace
方法将匹配到的电话号码格式替换为(***)-***-****
。
- 搜索日志文件中的错误信息
using System;
using System.IO;
using System.Text.RegularExpressions;
class Program
{
static void Main()
{
string logFile = "app.log";
string pattern = @"ERROR:\s.*";
try
{
string[] lines = File.ReadAllLines(logFile);
foreach (string line in lines)
{
if (Regex.IsMatch(line, pattern))
{
Console.WriteLine(line);
}
}
}
catch (IOException e)
{
Console.WriteLine($"Error reading file: {e.Message}");
}
}
}
解释:
ERROR:
:匹配ERROR:
字符串。\s
:匹配一个空白字符(通常是空格)。.*
:匹配任意字符(包括换行符)零次或多次,用于匹配错误信息的具体内容。
- 提取 HTML 标签内的文本
using System;
using System.Text.RegularExpressions;
class Program
{
static void Main()
{
string html = "<p>Hello, World!</p><div>Some content</div><span>Another text</span>";
string pattern = @">(.*?)<";
MatchCollection matches = Regex.Matches(html, pattern);
foreach (Match match in matches)
{
Console.WriteLine(match.Groups[1].Value);
}
}
}
解释:
>
:匹配 HTML 标签的结束符号。(.*?)
:这是一个非贪婪捕获组。.*
表示匹配任意字符零次或多次,?
表示非贪婪模式,即尽可能少地匹配字符,以找到第一个>
和<
之间的内容。<
:匹配 HTML 标签的开始符号。- 通过
Match.Groups[1].Value
获取捕获组中匹配的文本,即 HTML 标签内的文本内容。