在你进行下一步之前,让我们快速了解一下正则表达式的基本术语。
捕获:当你使用一个子表达式匹配一个正则表达式的结果。Capture和CaptureCollection类表示来自单个或一组成功的子表达式捕获的结果。
分组:一个正则表达式可以是一个或多个组组成。Group 类表示来自单个捕获组的结果。GroupCollection类表示一次匹配中捕获的组的集合。
匹配:正则表达式匹配后得到的结果。Match类表示单个正则表达式匹配的结果。MatchCollection 类
表示通过以迭代方式将正则表达式模式应用于输入字符串所找到的成功匹配的集合。
因此,正则表达式相关的对象之间的关系是:
Regex class --> MatchCollection --> Match objects --> GroupCollection --> Group objects --> CaptureCollection --> Capture objects
Regex 类
Regex 类表示 .NET Framework 的正则表达式引擎。它可用来快速分析大量的文本,以查找特定字符模式;提取、编辑、替换或删除文本子字符串;或将提取的字符串添加到集合中,以便生成报告。
你可以用两种方法使用Regex类,调用它静态方法或使用实例方法都可以,在性能上没有什么区别。下面列出了Regex类的一些主要方法:
方法 | 描述 |
IsMatch | IsMatch() 指示所指定的正则表达式在指定的输入字符串中是否找到了匹配项。如何匹配返回true,否则返回false。 |
Match | Match() 在该字符串中搜索正则表达式的第一个匹配项。匹配成功返回一个Match对象。 |
Matches | Matches() 在指定的输入字符串中搜索正则表达式的所有匹配项。 |
Replace | 使用指定的替换字符串替换与某个正则表达式模式匹配的所有字符串。 |
Split | 根据正则表达式模式定义拆分输入字符串,它返回一个字符串的数组。 |
在下面的章节中我们将会用到上面介绍的方法。
使用Regex类进行模式匹配
在本节中,我们将介绍Regex类的模式匹配能力。从创建一个新的控制台应用程序,并引用System.Text.RegularExpression命名空间开始。
using System.Text.RegularExpressions;
使用IsMatch()方法
下面的示例检查一个字符串是否是一个有效的URL。
static void Main(string[] args)
{
string source = args[0];
string pattern = @"http(s)?://([w-]+.)+[w-]+(/[w-./?%&=]*)?";
bool success = Regex.IsMatch(source, pattern);
if (success)
{
Console.WriteLine("Entered string is a valid URL!");
}
else
{
Console.WriteLine("Entered string is not a valid URL!");
}
Console.ReadLine();
}
Main()方法接收一个命令行参数,string pattern = @"http(s)?://([w-]+.)+[w-]+(/[w- ./?%&=]*)?";定义了URL的模式匹配。调用Regex的静态方法IsMatch来验证是否匹配。返回bool值来判断匹配是否成功。最终输出消息到控制台。
还可以使用Regex类的对象来调用IsMatch方法:
Regex ex = new Regex(pattern);
success = ex.IsMatch(source);
使用Match()方法
下面的示例演示如何使用Match方法:
static void Main(string[] args)
{
string source = args[0];
string pattern = @"http(s)?://([w-]+.)+[w-]+(/[w-./?%&=]*)?"; Match match = Regex.Match(source, pattern);
if(match.Success)
{
Console.WriteLine("Entered string is a valid URL!");
Console.WriteLine("{0} Groups教程", match.Groups.Count);
for(int i=0;i<match.Groups.Count;i++)
{
Console.WriteLine("Group {0} Value = {1} Status = {2}",
i, match.Groups[i].Value, match.Groups[i].Success);
Console.WriteLine("t{0} Captures", match.Groups[i].Captures.Count);
for (int j = 0; j < match.Groups[i].Captures.Count; j++)
{
Console.WriteLine("tt Capture {0} Value = {1} Found at = {2}",
j, match.Groups[i].Captures[j].Value, match.Groups[i].Captures[j].Index);
}
}
}
else
{
Console.WriteLine("Entered string is not a valid URL!");
}
Console.ReadLine();
}
上面的代码使用Match()方法来执行模式匹配。Match()方法返回Match类的对象,表示第一次出现的匹配。Math对象的Success属性告诉我们是否匹配成功。for循环遍历所有匹配组(GroupCollection对象)。此外,在循环内,再次迭代捕获组。并将捕获的值和索引位置输出。下图显示的是上诉程序的运行示例。
如图所示:一共包含4个匹配组。第一组的值是https://dev.mjxy.cn
第二组的值是 s 。第三组有两个值 dev. 和mjxy. 。第四组的值是 / 。
使用Matches()方法
Matches()方法和Match()类似,但是它返回一个Match对象的集合(MatchCollection)。然后,你可以遍历所有匹配的实例。如下代码演示:
static void Main(string[] args)
{
string source = args[0];
string pattern = @"http(s)?://([w-]+.)+[w-]+(/[w-./?%&=]*)?";
Match match = Regex.Match(source, pattern);
if (match.Success)
{
Console.WriteLine("Entered string is a valid URL!");
Console.WriteLine("{0} Groups", match.Groups.Count);
for (int i = 0; i < match.Groups.Count; i++)
{
Console.WriteLine("Group {0} Value = {1} Status = {2}",
i, match.Groups[i].Value, match.Groups[i].Success);
Console.WriteLine("t{0} Captures", match.Groups[i].Captures.Count);
for (int j = 0; j < match.Groups[i].Captures.Count; j++)
{
Console.WriteLine("tt Capture {0} Value = {1} Found at = {2}",
j, match.Groups[i].Captures[j].Value, match.Groups[i].Captures[j].Index);
}
}
}
else
{
Console.WriteLine("Entered string is not a valid URL!");
}
Console.ReadLine();
}
查找和替换字符串
Regex类除了匹配字符串,还可以查找可替换字符串。例如,你可以将需要匹配的字符串替换成任意你想要的内容。如下列代码:
static void Main(string[] args)
{
string source = args[0];
string pattern = @"http(s)?://([w-]+.)+[w-]+(/[w-./?%&=]*)?";
string result = Regex.Replace(source,pattern,"[*** URLs not allowed ***]");
Console.WriteLine(result);
Console.ReadLine();
}
在上面的代码中,正则表达式扫描输入的URL字符串。然后调用Regex类的Replace()方法。第一个参数是你希望在其中执行替换的字符串。第二个参数是规则,第三个参数是替换的结果字符串。如何你运行上面的代码,结果类型这样:
分拆字符串
Regex类允许你使用正则表达式分拆一个字符串。例如:日期字符串 2010-12-30,使用 / 来将日期的年月日分拆开单独的字符串。参见下面的代码示例:
string strDate = "2011-12-31";
string[] dates = Regex.Split(strDate, "-");
foreach (string s in dates)
{
Console.WriteLine(s);
}
Console.ReadLine();
结果如下图所示:
Regex的选项
None | 不可用 | 使用默认行为。 |
IgnoreCase | i | 使用不区分大小写的匹配。 |
Multiline | m | 使用多线模式,其中 ^ 和 $ 匹配每行的开头和末尾(不是输入字符串的开头和末尾)。 |
Singleline | s | Use single-line mode, where the period (.) matches every character (instead of every character except n). |
ExplicitCapture | n | 不捕获未命名的组。 唯一有效的捕获是显式命名或编号的 ((?<name> subexpression)) 形式的组。 |
Compiled | 不可用 | 将正则表达式编译为程序集。 |
IgnorePatternWhitespace | x | 从模式中排除保留的空白并启用数字符号 (#) 后的注释。 |
RightToLeft | 不可用 | 更改搜索方向。 搜索是从右向左而不是从左向右进行。 |
ECMAScript | 不可用 | 为表达式启用符合 ECMAScript 的行为。 |
CultureInvariant | 不可用 | 忽略语言的区域性差异。 有关固定区域性的更多信息,请参见 。 |
为了说明如何使用RegexOptions枚举可以用下面的代码写在main()方法,并观察由于RegexOptions值的差异。
static void Main(string[] args)
{
string source = args[0];
bool success1 = Regex.IsMatch(source, "hello");
Console.WriteLine("String found? {0}", success1);
bool success2 = Regex.IsMatch(source, "hello", RegexOptions.IgnoreCase);
Console.WriteLine("String found? {0}", success2);
Console.ReadLine();
}
正如你看到的,第二次调用IsMatch()方法使用RegexOptions枚举忽略大小写匹配。没有任何RegexOptions的返回false,使用RegexOptions.IgnoreCase返回true。
注意:
你可以组合RegexOptions的值使用:
bool success2 = Regex.IsMatch(source, "hello", RegexOptions.IgnoreCase | RegexOptions.Compiled);
性能和最佳做法
在大多数情况下,它将执行模式匹配快速且高效地。但是,在某些情况下,正则表达式引擎可以似乎是很慢。 在极端情况下甚至会出现停止响应,因为它的过程中几个小时甚至几天处理相对较小的输