C# 正则表达式应用:文本提取与输出
正则表达式(Regular Expression,简称 Regex)是一种强大的文本处理工具,它使用特定的模式来匹配、查找、替换和提取文本中的字符串。在 C# 中,System.Text.RegularExpressions
命名空间提供了正则表达式的支持,使得开发者能够轻松地处理各种复杂的文本操作。本文将深入探讨 C# 正则表达式的应用,重点关注文本提取与输出,并通过丰富的示例代码来展示其用法和技巧。
1. 正则表达式基础
在深入应用之前,我们首先需要了解正则表达式的基本语法和概念。
1.1. 元字符
元字符是正则表达式中具有特殊含义的字符,它们用于构建匹配模式。以下是一些常用的元字符:
.
:匹配除换行符以外的任何单个字符。*
:匹配前面的子表达式零次或多次。+
:匹配前面的子表达式一次或多次。?
:匹配前面的子表达式零次或一次。{n}
:匹配前面的子表达式恰好 n 次。{n,}
:匹配前面的子表达式至少 n 次。{n,m}
:匹配前面的子表达式至少 n 次,但不超过 m 次。[]
:匹配方括号中的任何一个字符。例如,[abc]
匹配 “a”、”b” 或 “c”。[^]
:匹配不在方括号中的任何一个字符。例如,[^abc]
匹配除 “a”、”b” 和 “c” 之外的任何字符。()
:将括号内的表达式分组为一个子表达式。|
:匹配两个或多个表达式中的任何一个。例如,a|b
匹配 “a” 或 “b”。^
:匹配字符串的开头。$
:匹配字符串的结尾。\
:转义字符,用于匹配特殊字符本身。例如,\.
匹配 “.”。\d
:匹配一个数字字符。等价于[0-9]
。\D
:匹配一个非数字字符。等价于[^0-9]
。\w
:匹配一个单词字符(字母、数字或下划线)。等价于[a-zA-Z0-9_]
。\W
:匹配一个非单词字符。等价于[^a-zA-Z0-9_]
。\s
:匹配一个空白字符(空格、制表符、换行符等)。\S
:匹配一个非空白字符。
1.2. 字符类
字符类是使用方括号 []
定义的一组字符,用于匹配其中的任何一个字符。例如:
[abc]
:匹配 “a”、”b” 或 “c”。[a-z]
:匹配任何小写字母。[A-Z]
:匹配任何大写字母。[0-9]
:匹配任何数字。[a-zA-Z0-9]
:匹配任何字母或数字。
1.3. 量词
量词用于指定子表达式出现的次数。例如:
a*
:匹配零个或多个 “a”。a+
:匹配一个或多个 “a”。a?
:匹配零个或一个 “a”。a{3}
:匹配恰好三个 “a”。a{3,}
:匹配至少三个 “a”。a{3,5}
:匹配三到五个 “a”。
1.4. 分组和捕获
使用圆括号 ()
可以将正则表达式的一部分分组为一个子表达式,并可以捕获匹配的文本。例如:
(ab)+
:匹配一个或多个 “ab”。(\d{3})-(\d{3})-(\d{4})
:匹配一个美国电话号码,并将区号、前缀和线路号分别捕获到三个组中。
1.5. 贪婪与非贪婪
默认情况下,量词是贪婪的,即它们会尽可能多地匹配字符。可以在量词后面加上 ?
使其变为非贪婪的,即尽可能少地匹配字符。例如:
<.*>
:贪婪匹配,会匹配整个 HTML 标签,包括其中的内容。<.*?>
:非贪婪匹配,会匹配最短的 HTML 标签。
2. C# 中的正则表达式类
System.Text.RegularExpressions
命名空间提供了以下几个关键类来支持正则表达式操作:
Regex
:表示一个正则表达式。Match
:表示正则表达式的匹配结果。MatchCollection
:表示Match
对象的集合。Group
:表示正则表达式中的一个捕获组。GroupCollection
:表示Group
对象的集合。Capture
:表示一个捕获组中的一个子字符串。CaptureCollection
: 表示Capture
对象的集合
2.1. Regex 类
Regex
类是 C# 中正则表达式的核心类,它提供了以下常用方法:
Regex(string pattern)
:构造函数,使用指定的正则表达式模式创建一个Regex
对象。Regex(string pattern, RegexOptions options)
: 构造函数, 使用指定的正则表达式和选项创建一个Regex
对象.IsMatch(string input)
:判断输入字符串是否与正则表达式匹配。Match(string input)
:在输入字符串中搜索正则表达式的第一个匹配项,并返回一个Match
对象。Matches(string input)
:在输入字符串中搜索正则表达式的所有匹配项,并返回一个MatchCollection
对象。Replace(string input, string replacement)
:将输入字符串中所有与正则表达式匹配的子字符串替换为指定的替换字符串。Split(string input)
:根据正则表达式的匹配项将输入字符串拆分为一个字符串数组。
2.2. Match 类
Match
类表示正则表达式的匹配结果,它提供了以下常用属性和方法:
Success
:表示匹配是否成功。Value
:表示匹配到的子字符串。Index
:表示匹配到的子字符串在输入字符串中的起始位置。Length
:表示匹配到的子字符串的长度。Groups
:表示一个GroupCollection
对象,包含所有捕获组的匹配结果。NextMatch()
: 从上一个匹配结束位置开始, 返回输入字符串中的下一个匹配项.
2.3. Group 类
Group
类表示正则表达式中的一个捕获组,它提供了以下常用属性:
Success
:表示捕获组是否成功匹配。Value
:表示捕获组匹配到的子字符串。Index
:表示捕获组匹配到的子字符串在输入字符串中的起始位置。Length
:表示捕获组匹配到的子字符串的长度。Captures
: 表示一个CaptureCollection
对象, 包含捕获组的所有子字符串。
3. 文本提取与输出示例
下面通过一些具体的示例来展示如何使用 C# 正则表达式进行文本提取和输出。
3.1. 提取电子邮件地址
“`csharp
using System;
using System.Text.RegularExpressions;
public class Example
{
public static void Main(string[] args)
{
string text = “联系我们:[email protected], [email protected]”;
string pattern = @”\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+.[A-Za-z]{2,}\b”;
MatchCollection matches = Regex.Matches(text, pattern);
foreach (Match match in matches)
{
Console.WriteLine("找到电子邮件地址:{0}", match.Value);
}
}
}
// 输出:
// 找到电子邮件地址:[email protected]
// 找到电子邮件地址:[email protected]
“`
解析:
\b
:匹配单词边界,确保匹配完整的电子邮件地址。[A-Za-z0-9._%+-]+
:匹配电子邮件地址的用户名部分,允许字母、数字、点、下划线、百分号、加号和减号。@
:匹配 “@” 符号。[A-Za-z0-9.-]+
:匹配电子邮件地址的域名部分,允许字母、数字、点和减号。\.
:匹配 “.”。[A-Za-z]{2,}
:匹配顶级域名,至少两个字母。
3.2. 提取电话号码
“`csharp
using System;
using System.Text.RegularExpressions;
public class Example
{
public static void Main(string[] args)
{
string text = “我的电话号码是:123-456-7890,另一个是 (555) 123-4567″;
string pattern = @”(?\d{3})?[-.\s]?\d{3}[-.\s]?\d{4}”;
MatchCollection matches = Regex.Matches(text, pattern);
foreach (Match match in matches)
{
Console.WriteLine("找到电话号码:{0}", match.Value);
}
}
}
// 输出:
// 找到电话号码:123-456-7890
// 找到电话号码:(555) 123-4567
“`
解析:
\(?
:匹配可选的左括号。\d{3}
:匹配三个数字。\)?
:匹配可选的右括号。[-.\s]?
:匹配可选的连字符、点或空格。\d{3}
:匹配三个数字。[-.\s]?
:匹配可选的连字符、点或空格。\d{4}
:匹配四个数字。
3.3. 提取 HTML 标签中的链接
“`csharp
using System;
using System.Text.RegularExpressions;
public class Example
{
public static void Main(string[] args)
{
string text = “Example, Domain“;
string pattern = ““;
MatchCollection matches = Regex.Matches(text, pattern);
foreach (Match match in matches)
{
Console.WriteLine("找到链接:{0}", match.Groups[1].Value);
}
}
}
// 输出:
// 找到链接:https://www.example.com
// 找到链接:https://www.domain.net
“`
解析:
<a href=\"
:匹配 “<a href=\””。(.*?)
:使用非贪婪模式匹配链接地址,并将其捕获到第一个组中。\">
:匹配 “\”>”。match.Groups[1].Value
:访问第一个捕获组中匹配到的值。
3.4. 提取日期
“`csharp
using System;
using System.Text.RegularExpressions;
public class Example
{
public static void Main(string[] args)
{
string text = “今天的日期是 2023-10-27,明天的日期是 2023/10/28”;
string pattern = @”\b(\d{4})-/-/\b”;
MatchCollection matches = Regex.Matches(text, pattern);
foreach (Match match in matches)
{
Console.WriteLine("找到日期:{0}-{1}-{2}", match.Groups[1].Value, match.Groups[2].Value, match.Groups[3].Value);
}
}
}
// 输出:
// 找到日期:2023-10-27
// 找到日期:2023-10-28
“`
解析:
\b
:匹配单词边界。(\d{4})
:匹配四位数字的年份,并将其捕获到第一个组中。[-/]
:匹配连字符或斜杠。(\d{2})
:匹配两位数字的月份,并将其捕获到第二个组中。[-/]
:匹配连字符或斜杠。(\d{2})
:匹配两位数字的日期,并将其捕获到第三个组中。\b
:匹配单词边界。match.Groups[1].Value
,match.Groups[2].Value
,match.Groups[3].Value
:分别访问年、月、日的捕获组。
3.5 提取日志文件中的信息
假设有如下日志文件内容:
2023-10-27 10:00:00 INFO: User logged in: JohnDoe
2023-10-27 10:01:30 ERROR: Failed to connect to database
2023-10-27 10:05:15 WARNING: Disk space is low
我们可以使用正则表达式提取日志中的日期、时间、级别和消息:
“`csharp
using System;
using System.Text.RegularExpressions;
public class Example
{
public static void Main(string[] args)
{
string logText = @”
2023-10-27 10:00:00 INFO: User logged in: JohnDoe
2023-10-27 10:01:30 ERROR: Failed to connect to database
2023-10-27 10:05:15 WARNING: Disk space is low
“;
string pattern = @”(\d{4}-\d{2}-\d{2})\s+(\d{2}:\d{2}:\d{2})\s+(\w+):\s+(.*)”;
MatchCollection matches = Regex.Matches(logText, pattern);
foreach (Match match in matches)
{
Console.WriteLine("日期:{0}", match.Groups[1].Value);
Console.WriteLine("时间:{0}", match.Groups[2].Value);
Console.WriteLine("级别:{0}", match.Groups[3].Value);
Console.WriteLine("消息:{0}", match.Groups[4].Value);
Console.WriteLine("---");
}
}
}
//输出:
//日期:2023-10-27
//时间:10:00:00
//级别:INFO
//消息:User logged in: JohnDoe
//—
//日期:2023-10-27
//时间:10:01:30
//级别:ERROR
//消息:Failed to connect to database
//—
//日期:2023-10-27
//时间:10:05:15
//级别:WARNING
//消息:Disk space is low
//—
“`
解析:
(\d{4}-\d{2}-\d{2})
:匹配日期,并将其捕获到第一个组中。\s+
:匹配一个或多个空格。(\d{2}:\d{2}:\d{2})
:匹配时间,并将其捕获到第二个组中。\s+
:匹配一个或多个空格。(\w+)
:匹配日志级别(INFO、ERROR、WARNING 等),并将其捕获到第三个组中。:\s+
:匹配冒号和后面的一个或多个空格。(.*)
:匹配日志消息,并将其捕获到第四个组中。
4. 正则表达式选项
RegexOptions
枚举提供了一些选项来控制正则表达式的匹配行为。以下是一些常用的选项:
IgnoreCase
:忽略大小写。Multiline
:多行模式,^
和$
匹配每一行的开头和结尾,而不是整个字符串的开头和结尾。Singleline
:单行模式,.
匹配任何字符,包括换行符。Compiled
:将正则表达式编译为程序集,提高匹配速度,但会增加启动时间。IgnorePatternWhitespace
:忽略正则表达式模式中的空白字符和注释。RightToLeft
: 从右向左扫描字符串.
可以使用按位或运算符 |
组合多个选项。例如:
csharp
Regex regex = new Regex("pattern", RegexOptions.IgnoreCase | RegexOptions.Multiline);
5. 性能优化
正则表达式的性能可能会受到模式复杂度和输入字符串长度的影响。以下是一些优化正则表达式性能的建议:
- 使用简单的模式:避免使用过于复杂的正则表达式,尽量使用简洁明了的模式。
- 避免回溯:回溯是正则表达式引擎尝试不同匹配路径的过程,过多的回溯会导致性能下降。可以使用非贪婪量词、原子分组等技巧来减少回溯。
- 使用
Compiled
选项:对于需要频繁使用的正则表达式,可以使用Compiled
选项将其编译为程序集,提高匹配速度。 - 预编译正则表达式:如果一个正则表达式需要多次使用,可以将其预编译为一个
Regex
对象,避免重复编译。 - 使用非捕获组:如果不需要捕获某个分组的内容,可以使用非捕获组
(?:...)
,减少内存开销。
6. 总结
C# 正则表达式是一种强大的文本处理工具,可以用于各种文本提取、替换、验证和格式化任务。本文详细介绍了 C# 正则表达式的基础知识、常用类和方法,并通过丰富的示例代码展示了其在实际应用中的用法。掌握正则表达式可以大大提高开发效率,使文本处理变得更加轻松。
希望这篇文章能够帮助您深入理解 C# 正则表达式的应用,并在您的开发工作中发挥作用。