前面两篇讲述了正则表达式的基础和一些简单的例子,这篇将稍微深入一点探讨一下正则表达式分组,在.NET中正则表达式分组是用Math类来代表的。
首先先看一段代码:

/// <summary>
/// 显示Match内多个Group的例子
/// </summary>
public void ShowStructure()
{
        //要匹配的字符串
        string text = "1A 2B 3C 4D 5E 6F 7G 8H 9I 10J 11Q 12J 13K 14L 15M 16N ffee80 #800080";
        //正则表达式
        string pattern = @"((\d+)([a-z]))\s+";
        //使用RegexOptions.IgnoreCase枚举值表示不区分大小写
        Regex r = new Regex(pattern, RegexOptions.IgnoreCase);
        //使用正则表达式匹配字符串,仅返回一次匹配结果
        Match m = r.Match(text);
        while (m.Success)
        {

                //显示匹配开始处的索引值和匹配到的值
                System.Console.WriteLine("Match=[" + m + "]");
                CaptureCollection cc = m.Captures;
                foreach (Capture c in cc)
                {
                        Console.WriteLine("\tCapture=[" + c + "]");
                }
                for (int i = 0; i < m.Groups.Count; i++)
                {
                        Group group = m.Groups[i];
                        System.Console.WriteLine("\t\tGroups[{0}]=[{1}]", i, group);
                        for (int j = 0; j < group.Captures.Count; j++)
                        {
                                Capture capture = group.Captures[j];
                                Console.WriteLine("\t\t\tCaptures[{0}]=[{1}]", j, capture);
                        }
                }
                //进行下一次匹配.
                m = m.NextMatch();
        }
}

这段代码的执行效果如下:
Match=[1A ]
    Capture=[1A ]
        Groups[0]=[1A ]
            Captures[0]=[1A ]
        Groups[1]=[1A]
            Captures[0]=[1A]
        Groups[2]=[1]
            Captures[0]=[1]
        Groups[3]=[A]
            Captures[0]=[A]
Match=[2B ]
    Capture=[2B ]
        Groups[0]=[2B ]
            Captures[0]=[2B ]
        Groups[1]=[2B]
            Captures[0]=[2B]
        Groups[2]=[2]
            Captures[0]=[2]
        Groups[3]=[B]
            Captures[0]=[B]
..................此去省略一些结果
Match=[16N ]
    Capture=[16N ]
        Groups[0]=[16N ]
            Captures[0]=[16N ]
        Groups[1]=[16N]
            Captures[0]=[16N]
        Groups[2]=[16]
            Captures[0]=[16]
        Groups[3]=[N]
            Captures[0]=[N]
通过对上面的代码结合代码的分析,我们得出下面的结论,在((\d+)([a-z]))\s+这个正则表达式里总共包含了四个Group,即分组,按照默认的从左到右的匹配方式,其中Groups[0]代表了整个分组,其它的则是子分组,用示意图表示如下:
 
在上面的代码中是采用了Regex类的Match()方法,调用这种方法返回的是一个Match,要处理分析全部的字符串,还需要在while循环的中通过Match类的NextMatch()方法返回下一个可能成功的匹配(可通过Match类的Success属性来判断是否成功匹配)。上面的代码还可以写成如下形式:

/// <summary>
/// 使用Regex类的Matches方法所有所有的匹配
/// </summary>
public void Matches()
{
        //要匹配的字符串
        string text = "1A 2B 3C 4D 5E 6F 7G 8H 9I 10J 11Q 12J 13K 14L 15M 16N ffee80 #800080";
        //正则表达式
        string pattern = @"((\d+)([a-z]))\s+";
        //使用RegexOptions.IgnoreCase枚举值表示不区分大小写
        Regex r = new Regex(pattern, RegexOptions.IgnoreCase);
        //使用正则表达式匹配字符串,返回所有的匹配结果
        MatchCollection matchCollection = r.Matches(text);
        foreach (Match m in matchCollection)
        {
                //显示匹配开始处的索引值和匹配到的值
                System.Console.WriteLine("Match=[" + m + "]");
                CaptureCollection cc = m.Captures;
                foreach (Capture c in cc)
                {
                        Console.WriteLine("\tCapture=[" + c + "]");
                }
                for (int i = 0; i < m.Groups.Count; i++)
                {
                        Group group = m.Groups[i];
                        System.Console.WriteLine("\t\tGroups[{0}]=[{1}]", i, group);
                        for (int j = 0; j < group.Captures.Count; j++)
                        {
                                Capture capture = group.Captures[j];
                                Console.WriteLine("\t\t\tCaptures[{0}]=[{1}]", j, capture);
                        }
                }
        }
}

上面的这段代码和采用While循环遍历所有匹配的结果是一样的,在实际情况中有可能出现不需要全部匹配而是从某一个位置开始匹配的情况,比如从第32个字符处开始匹配,这种要求可以通过Match()或者Matches()方法的重载方法来实现,仅需要将刚才的实例代码中的MatchCollection matchCollection = r.Matches(text);改为MatchCollection matchCollection = r.Matches(text,48);就可以了。

输出结果如下:
Match=[5M ]
        Capture=[5M ]
                Groups[0]=[5M ]
                        Captures[0]=[5M ]
                Groups[1]=[5M]
                        Captures[0]=[5M]
                Groups[2]=[5]
                        Captures[0]=[5]
                Groups[3]=[M]
                        Captures[0]=[M]
Match=[16N ]
        Capture=[16N ]
                Groups[0]=[16N ]
                        Captures[0]=[16N ]
                Groups[1]=[16N]
                        Captures[0]=[16N]
                Groups[2]=[16]
                        Captures[0]=[16]
                Groups[3]=[N]
                        Captures[0]=[N]
注意上面的MatchCollection matchCollection = r.Matches(text,48)表示从text字符串的位置48处开始匹配,要注意位置0位于整个字符串的之前,位置1位于字符串中第一个字符之后第二个字符之前,示意图如下(注意是字符串“1A”与“2B”之间有空格):
 
在text的位置48处正好是15M中的5处,因此返回的第一个Match是5M而不是15M。这里还继续拿出第一篇中的图来,如下:
 
从上图可以看出Capture、Group及Match类之间存在继承关系,处在继承关系顶端的Capture类中就定义了Index、Length和Value属性,其中Index表示原始字符串中发现捕获子字符串的第一个字符的出现位置,Length属性表示子字符串的长度,而Value属性表示从原始字符串中捕获的子字符串,利用这些属性可以实现一些比较复杂的应用。例如在现在还有很多论坛仍没有使用所见即所得的在线编辑器,而是使用了一种UBB编码的编辑器,使用所见即所得的编辑器存在着一定的安全风险,比如可以在源代码中嵌入js代码或者其它恶意代码,这样浏览者访问时就会带来安全问题,而使用UBB代码就不会代码这个问题,因为UBB代码包含了有限的、但不影响常规使用的标记并且支持UBB代码的编辑器不允许直接在字符串中出现HTML代码,也而就避免恶意脚本攻击的问题。在支持UBB代码的编辑器中输入的文本在存入数据库中保存的形式是UBB编码,显示的时候需要将UBB编码转换成HTML代码,例如下面的一段代码就是UBB编码:
[url]http://zhoufoxcn.blog.51cto.com[/url][url=http://blog.csdn.net/zhoufoxcn]周公的专栏[/url]
下面通过例子演示如何将上面的UBB编码转换成HTML代码:

/// <summary>
/// 下面的代码实现将文本中的UBB超级链接代码替换为HTML超级链接代码
/// </summary>
public void UBBDemo()
{
        string text = "[url=http://zhoufoxcn.blog.51cto.com][/url][url=http://blog.csdn.net/zhoufoxcn]周公的专栏[/url]";
        Console.WriteLine("原始UBB代码:" + text);
        Regex regex = new Regex(@"(\[url=([ \S\t]*?)\])([^[]*)(\[\/url\])", RegexOptions.IgnoreCase);
        MatchCollection matchCollection = regex.Matches(text);
        foreach (Match match in matchCollection)
        {
                string linkText = string.Empty;
                //如果包含了链接文字,如第二个UBB代码中存在链接名称,则直接使用链接名称
                if (!string.IsNullOrEmpty(match.Groups[3].Value))
                {
                        linkText = match.Groups[3].Value;
                }
                else//否则使用链接作为链接名称
                {
                        linkText = match.Groups[2].Value;
                }
                text = text.Replace(match.Groups[0].Value, "<a href=\"" + match.Groups[2].Value + "\" target=\"_blank\">"+ linkText + "</a>");
        }
        Console.WriteLine("替换后的代码:"+text);

}

程序执行结果如下:

原始UBB代码:[url=http://zhoufoxcn.blog.51cto.com][/url][url=http://blog.csdn.net/zhoufoxcn]周公的专栏[/url]
替换后的代码:<a href="http://zhoufoxcn.blog.51cto.com" target="_blank">http://zhoufoxcn.blog.51cto.com</a><a href="http://blog.csdn.net/zhoufoxcn"target="_blank">周公的专栏</a>

上面的这个例子就稍微复杂点,对于初学正则表达式的朋友来说,可能有点难于理解,不过没有关系,后面我会讲讲正则表达式。在实际情况下,可能通过match.Groups[0].Value这种方式不太方便,就想在访问DataTable时写string name=dataTable.Rows[i][j]这种方式一样,一旦再次调整,这种通过索引的方式极容易出错,实际上我们也可以采用名称而不是索引的放来来访问Group分组,这个也会在以后的篇幅中去讲。

本文转自周金桥51CTO博客,原文链接: http://blog.51cto.com/zhoufoxcn/281956,如需转载请自行联系原作者

C#正则表达式编程(三):Match类和Group类用法相关推荐

  1. C# 正则表达式类 Match类和Group类

    Match类 示例:查找出字符串中包含的url string text = "FirstUrl: http://www.sohu.com ,SecondUrl: http://www.bai ...

  2. C#正则表达式编程(二):Regex类用法

    上一篇讲述了在C#中有关正则表达式的类之间的关系,以及它们的方法,这一篇主要是将Regex这个类的用法的,关于Match及MatchCollection类会在下一篇讲到. 对于正则表达式的应用,基本上 ...

  3. .NET中的正则表达式 (三)RegexCompilationInfo 类

    RegexCompilationInfo 类 提供编译器用于将正则表达式编译为独立程序集的信息. 属性 IsPublic:获取或设置一个值,该值指示所编译的正则表达式是否具有公共可见性. Name:获 ...

  4. java matcher.group_详解正则表达式Matcher类中group方法

    前言 同事把一个excel表给我,里面的数据大概有几千的样子吧.自己需要把里面的数据一个一个拿出来做一个http请求,对得到的结果进行过滤,然后再写到上面去.这是就涉及到用脚本来进行操作了,于是自己搞 ...

  5. python创建线程函数_Python多线程编程(三):threading.Thread类的重要函数和方法...

    这篇文章主要介绍threading模块中的主类Thread的一些主要方法,实例代码如下: 复制代码 代码如下: ''' Created on 2012-9-7 @author:  walfred @m ...

  6. [Java 并发编程实战] 设计线程安全的类的三个方式(含代码)

    发奋忘食,乐以忘优,不知老之将至.---<论语> 前面几篇已经介绍了关于线程安全和同步的相关知识,那么有了这些概念,我们就可以开始着手设计线程安全的类.本文将介绍构建线程安全类的几个方法, ...

  7. 【C#进阶二】C#中的正则表达式知识总结(字符转义/字符类/ 定位点/ 分组构造 /数量词/反向引用构造/替换构造/替代/正则表达式选项)(理论篇)

    文章目录 0. 正则表达式网站推荐 1.字符转义 2.字符类 3. 定位点 4. 分组构造 5.数量词 6.反向引用构造 7.替换构造 8.替代 9.正则表达式选项 正则表达式是对字符串操作的一种逻辑 ...

  8. Python 核心编程(三)

    Python 核心编程 第三章 正则表达式 ​ 在开发中会有大量的字符串处理工作,其中经常会涉及到字符串格式的校验. 思考1 ​ 场景:如何判断一个字符串是手机号呢? ​ 测试文件 aesdf1381 ...

  9. Java—正则表达式(Pattern类和Matcher类)

    正则表达式介绍   正则表达式可以用于对字符串的处理,相当于是一个匹配字符串的模板.主要包含查找.替换.分割.提取等操作:Java中通过Pattern和Matcher类提供对正则的支持. 字符处理 特 ...

最新文章

  1. 我也能做CTO之程序员职业规划
  2. linux docker 目录挂载映射
  3. 有感而发,恍然大悟。
  4. Golang + Goland环境配置 + Goland破解
  5. Invalid connection string format, a valid format is: host:port:sid
  6. 脱机下载至校验成功的脚本
  7. 佳能c3320怎么设置接收方_入门级单反相机佳能800D是否值得买?在我看来价格决定一切...
  8. 机器学习领域有哪一些值得关注的人
  9. Angular项目中核心模块core Module只加载一次的实现
  10. leetcode题解8-盛最多水的容器
  11. hibernate mysql 注解_【译】Spring 4 + Hibernate 4 + Mysql + Maven集成例子(注解 + XML)
  12. C++之文件操作探究(三):写文件——二进制文件
  13. SQL Sever 常用语句总结
  14. Linux下如何禁止某个用户登录方法
  15. kindle刷机ttl_kindle paper white 2 (kpw) 无限重启救砖方法
  16. ae导出gif插件_AE脚本-快速输出GIF动图格式插件脚本 GifGun 1.7.7 Win/Mac 支持AE CC 2019...
  17. 线阵相机与面阵相机的区别及其应用
  18. R-CNN文章详细解读
  19. python连接mysql输出数据库结构docx文档
  20. Django 之ORM(一)

热门文章

  1. UVA - 11584 Partitioning by Palindromes(划分成回文串)(dp)
  2. Basic Sorting Algorithms
  3. JavaScript面向对象编程(1)-- 基础
  4. 图解ecshop之批量上传与批量处理
  5. 云计算五种定义辨析[摘]
  6. Mac 安装laravel 框架
  7. Win64 驱动内核编程-22.SHADOW SSDT HOOK(宋孖健)
  8. hdu4267线段树段更新,点查找,55棵线段树.
  9. 【C++ 语言】智能指针 引入 ( 内存泄漏 | 智能指针简介 | 简单示例 )
  10. 【约束布局】ConstraintLayout 之 Chains 链式约束 ( Chains 简介 | 代码 及 布局分析 | 链头设置 | 间距设置 | 风格设置 | 权重设置 )