解读C#中的正则表达式
本文摘自LTP.NET知识库。
regexp规则类包含在System.Text.RegularExpressions.dll文件中,在对应用软件进行编译时你必须引用这个文件:
System.Text.RegularExpressions.dll
名字空间简介
在名字空间中仅仅包含着6个类和一个定义,它们是:
Capture: 包含一次匹配的结果;
CaptureCollection: Capture的序列;
Group: 一次组记录的结果,由Capture继承而来;
Match: 一次表达式的匹配结果,由Group继承而来;
MatchCollection: Match的一个序列;
MatchEvaluator: 执行替换操作时使用的代理;
Regex: 编译后的表达式的实例。
Regex类中还包含一些静态的方法
Escape: 对字符串中的regex中的转义符进行转义;
IsMatch: 如果表达式在字符串中匹配,该方法返回一个布尔值;
Match: 返回Match的实例;
Matches: 返回一系列的Match的方法;
Replace: 用替换字符串替换匹配的表达式;
Split: 返回一系列由表达式决定的字符串;
Unescape:不对字符串中的转义字符转义。
简单匹配
先从使用Regex、Match类的简单表达式开始学习。
Match m = Regex.Match("abracadabra", "(a|b|r)+");
例:
if (m.Success)...
如果想使用匹配的字符串,可以把它转换成一个字符串:
Console.WriteLine("Match="+m.ToString());
输出: Match=abra。
这就是匹配的字符串。
字符串的替换
简单字符串的替换非常直观。
例如下面的语句:
string s = Regex.Replace("abracadabra", "abra", "zzzz");
它返回字符串zzzzcadzzzz,所有匹配的字符串都被替换成了zzzzz。
现在我们来看一个比较复杂的字符串替换的例子:
string s = Regex.Replace(" abra ", @"^\s(.?)\s*$", "$1");
这个语句返回字符串abra,其前导和后缀的空格都去掉了。
上面的模式对于删除任意字符串中的前导和后续空格都非常有用。
在C#中,我们还经常使用字母字符串,在一个字母字符串中,编译程序不把字符“ ” 作为转义字符处理。在使用字符“”指定转义字符时,@"..."是非常有用的。
另外值得一提的是$1在字符串替换方面的使用,它表明替换字符串只能包含被替换的字符串。
匹配引擎的细节
接下来通过一个组结构来理解一个稍微复杂的例子:
string text = "abracadabra1abracadabra2abracadabra3";
string pat = @"
    ( # 第一个组的开始
     abra # 匹配字符串abra
     ( # 第二个组的开始
     cad # 匹配字符串cad
     )? # 第二个组结束(可选)
    ) # 第一个组结束
    + # 匹配一次或多次
    ";
  //利用x修饰符忽略注释
  Regex r = new Regex(pat, "x");
  //获得组号码的清单
  int[] gnums = r.GetGroupNumbers();
  //首次匹配
  Match m = r.Match(text);
  while (m.Success)
   {
  //从组1开始
   for (int i = 1; i < gnums.Length; i++)
{
Group g = m.Group(gnums[i]);
  //获得这次匹配的组
    Console.WriteLine("Group"+gnums[i]+"=["+g.ToString()+"]");
  //计算这个组的起始位置和长度
    CaptureCollection cc = g.Captures;
for (int j = 0; j < cc.Count; j++)
{
Capture c = cc[j];
Console.WriteLine(" Capture" + j + "=["+c.ToString()
+ "] Index=" + c.Index + " Length=" + c.Length);
     }
    }
  //下一个匹配
   m = m.NextMatch();
   }
这个例子的输出如下所示:
Group1=[abra]
Capture0=[abracad] Index=0 Length=7
Capture1=[abra] Index=7 Length=4
Group2=[cad]
Capture0=[cad] Index=4 Length=3
Group1=[abra]
Capture0=[abracad] Index=12 Length=7
Capture1=[abra] Index=19 Length=4
Group2=[cad]
Capture0=[cad] Index=16 Length=3
Group1=[abra]
Capture0=[abracad] Index=24 Length=7
Capture1=[abra] Index=31 Length=4
Group2=[cad]
      Capture0=[cad] Index=28 Length=3
我们首先从考查字符串pat开始,pat中包含有表达式。
第一个capture是从第一个圆括号开始的,然后表达式将匹配到一个abra。
第二个capture组从第二个圆括号开始,但第一个capture组还没有结束,这意味着第一个组匹配的结果是abracad ,而第二个组的匹配结果仅仅是cad。
因此如果通过使用?符号而使cad成为一项可选的匹配,匹配的结果就可能是abra或abracad。
然后,第一个组就会结束,通过指定+符号要求表达式进行多次匹配。
现在我们来看看匹配过程中发生的情况。
首先,通过调用Regex的constructor方法建立表达式的一个实例,并在其中指定各种选项。
在这个例子中,由于在表达式中有注释,因此选用了x选项,另外还使用了一些空格。
打开x选项,表达式将会忽略注释和其中没有转义的空格。
然后,取得表达式中定义的组的编号的清单。
你当然可以显性地使用这些编号,在这里使用的是编程的方法。
如果使用了命名的组,作为一种建立快速索引的途径这种方法也十分有效。
接下来是完成第一次匹配。
通过一个循环测试当前的匹配是否成功,接下来是从group 1开始重复对组清单执行这一操作。
在这个例子中没有使用group 0的原因是group 0是一个完全匹配的字符串,如果要通过收集全部匹配的字符串作为一个单一的字符串,就会用到group 0了。
我们跟踪每个group中的CaptureCollection。
通常情况下每次匹配、每个group中只能有一个capture,但本例中的Group1则有两个capture:Capture0和Capture1。
如果你仅需要Group1的ToString,就会只得到abra,当然它也会与abracad匹配。
组中ToString的值就是其CaptureCollection中最后一个Capture的值,这正是我们所需要的。
如果你希望整个过程在匹配abra后结束,就应该从表达式中删除+符号,让regex引擎知道我们只需要对表达式进行匹配。
基于过程和基于表达式方法的比较
一般情况下,使用正则表达式的用户可以分为以下二大类:
第一类用户尽量不使用正则表达式,而是使用过程来执行一些需要重复的操作;
第二类用户则充分利用正则表达式处理引擎的功能和威力,而尽可能少地使用过程。
对于我们大多数用户而言,最好的方案莫过于二者兼而用之了。
希望这篇文章能够说明.NET语言中regexp类的作用以及它在性能和复杂性之间的优、劣点。
基于过程的模式
我们在编程中经常需要用到的一个功能是对字符串中的一部分进行匹配或其他一些对字符串处理,下面是一个对字符串中的单词进行匹配的例子:
string text = "the quick red fox jumped over the lazy brown dog.";
System.Console.WriteLine("text=[" + text + "]");
string result = "";
string pattern = @"\w+|\W+";
foreach (Match m in Regex.Matches(text, pattern))
{
  // 取得匹配的字符串
   string x = m.ToString();
  // 如果第一个字符是小写
   if (char.IsLower(x[0]))
  // 变成大写
  x = char.ToUpper(x[0]) + x.Substring(1, x.Length-1);
  // 收集所有的字符
   result += x;
}
System.Console.WriteLine("result=[" + result + "]");
正象上面的例子所示,我们使用了C#语言中的foreach语句处理每个匹配的字符,并完成相应的处理,在这个例子中,新创建了一个result字符串。
这个例子的输出所下所示:
text=[the quick red fox jumped over the lazy brown dog.]
result=[The Quick Red Fox Jumped Over The Lazy Brown Dog.]
基于表达式的模式
完成上例中的功能的另一条途径是通过一个MatchEvaluator,新的代码如下所示:
static string CapText(Match m)
{
//取得匹配的字符串
string x = m.ToString();
// 如果第一个字符是小写
if (char.IsLower(x[0]))
// 转换为大写
return char.ToUpper(x[0]) + x.Substring(1, x.Length-1);
return x;
}
static void Main()
{
string text = "the quick red fox jumped over the
lazy brown dog.";
System.Console.WriteLine("text=[" + text + "]");
string pattern = @"\w+";
string result = Regex.Replace(text, pattern,
new MatchEvaluator(Test.CapText));
System.Console.WriteLine("result=[" + result + "]");
    }
同时需要注意的是,由于仅仅需要对单词进行修改而无需对非单词进行修改,这个模式显得非常简单。
本文来自木庄网络博客> 解读C#中的正则表达式
解读C#中的正则表达式的更多相关文章
- 浅谈JavaScript中的正则表达式(适用初学者观看)
		
浅谈JavaScript中的正则表达式 1.什么是正则表达式(RegExp)? 官方定义: 正则表达式是一种特殊的字符串模式,用于匹配一组字符串,就好比用模具做产品,而正则就是这个模具,定义一种规则去 ...
 - PHP中有关正则表达式的函数集锦
		
之前学正则表达式的目的是想从网上抓取点小说啊,文档啊,还有获取相应的视频连接然后批量下载.当时初学PHP根本不知道PHP有专门抓包的工具,就像Simple_html_dom.php(在我的其他博文中有 ...
 - JavaScript中的正则表达式(终结篇)
		
JavaScript中的正则表达式(终结篇) 在之前的几篇文章中,我们了解了正则表达式的基本语法,但那些语法不是针对于某一个特定语言的.这篇博文我们将通过下面几个部分来了解正则表达式在JavaScri ...
 - Coursera-Getting and Cleaning Data-week4-R语言中的正则表达式以及文本处理
		
博客总目录:http://www.cnblogs.com/weibaar/p/4507801.html Thursday, January 29, 2015 补上第四周笔记,以及本次课程总结. 第四周 ...
 - 9.JAVA中的正则表达式
		
一.JAVA中的正则表达式 1.概念:以某种特定的方式描述字符串 1.Java中正则表达式的规则 ? #{0,1}-?有一个-或者没有 \\ #表示一个" ...
 - Python::re 模块 -- 在Python中使用正则表达式
		
前言 这篇文章,并不是对正则表达式的介绍,而是对Python中如何结合re模块使用正则表达式的介绍.文章的侧重点是如何使用re模块在Python语言中使用正则表达式,对于Python表达式的语法和详细 ...
 - 工作随笔——UIButton的EdgeInsets + Swift中的正则表达式;
		
1.UIButton的EdgeInsets UIButton的EdgeInsets方法,是用来设置title和image对于上左下右四个方向的偏移,但是很奇怪的是,刚开始只有Image,titile也 ...
 - Javascript中的正则表达式
		
Javascript中的正则表达式 刚开始接触正则表达式的时候,觉得这是个很死板的东西(没办法,计算机不能像人眼一样能很快的辨认出我们需要的结果,它需要一定的规则来对它进行限制),了解的越多,发现这个 ...
 - 在Visual Studio中使用正则表达式匹配换行和批量替换
		
系统环境:Windows 8.1 Enterprise Update 2 x64 开发环境:Mircosoft Visual Studio Ultimate 2013 Update 2 RC 问题:如 ...
 
随机推荐
- 搭建Nuget服务器(Nuget私服)
			
一.前言 对公司或者对个人来说,经过一段时间的沉淀之后,都会有一些框架或者模块,为了对这些框架或者模块进行更好的管理和维护,也为了方便后面的开发或者其他同事,我们可以在我们本地或者内网搭建一个Nuge ...
 - PythonI/O进阶学习笔记_5.python的set和dict
			
前言: 我一直觉得对我来说学习知识很忌讳不系统.本篇内容与上一篇 自定义序列类是有联系的. 上一篇比较通范的了解了序列类的一些协议和特性,并且有些list的内容.这篇更加具体到set和dict这两个序 ...
 - Android程序员接下来的路该如何走?
			
随着“5G”(第五代移动通信技术)商用进程越来越快,各个芯片和终端厂商们都已经开始布局准备,想必智能手机会是消费者最先能够接触到5G的重要终端,而和其相辅相生的移动互联网也势必会有新的发展. 但是和行 ...
 - Golang 入门系列(十五)如何理解go的并发?
			
前面已经讲过很多Golang系列知识,感兴趣的可以看看以前的文章,https://www.cnblogs.com/zhangweizhong/category/1275863.html, 接下来要说的 ...
 - Lucene 全文检索入门
			
博客地址:http://www.moonxy.com 一.前言 Lucene 是 apache 软件基金会的一个子项目,由 Doug Cutting 开发,是一个开放源代码的全文检索引擎工具包,但它不 ...
 - abp(net core)+easyui+efcore实现仓储管理系统——EasyUI之货物管理一 (十九)
			
abp(net core)+easyui+efcore实现仓储管理系统目录 abp(net core)+easyui+efcore实现仓储管理系统——ABP总体介绍(一) abp(net core)+ ...
 - logback配置方法
			
logback是一个通用可靠.快速灵活的日志框架,它替代了log4j,和slf4j组成新的日志系统. slf4j是一个日志门面,为其他各种日志框架提供了统一的接口,代码中使用slf4j可以避免对某一种 ...
 - html常见的块元素与内联(行内)元素用法说明(一)
			
html平时常见的块元素有:div, p, h1, h2, h3等,内联元素有:span, a, img等. 块元素的属性:无论内容是什么,都会独占一整行.主要用于页面布局. 内联元素的属性:只占自身 ...
 - Docker下实战zabbix三部曲之二:监控其他机器
			
在上一章<Docker下实战zabbix三部曲之一:极速体验>中,我们快速安装了zabbix server,并登录管理页面查看了zabbix server所在机器的监控信息,但是在实际场景 ...
 - Python 之父的解析器系列之七:PEG 解析器的元语法
			
原题 | A Meta-Grammar for PEG Parsers 作者 | Guido van Rossum(Python之父) 译者 | 豌豆花下猫("Python猫"公众 ...