对以下正则单步分解小块详细解说一下,如何写这样的正则
 //委托方法
        private string RegReplace(Match m)
        {
            Regex regValue = new Regex(@"(?<=showCabinInfo\(\s*)('[^']*',?)+(?=\))");
            return regValue.Match(m.Groups["values"].Value).Value + "," + m.Groups["content"].Value + "~"; 
        }Regex regSpan = new Regex(@"(?is)(?<=<td[^>]*>[^<]*(<span[^>]*>(?:(?!</?span\b).)*</span>\s*)*)\s*<span(?<values>[^>]*)>\s*(?<content>(?:(?!</?span\b).)*)(?<!\s)\s*</span>\s*(?=(<span[^>]*>(?:(?!</?span\b).)*</span>\s*)*</td>)"); string result = regSpan.Replace(test, new MatchEvaluator(RegReplace));
        richTextBox2.Text = result;

解决方案 »

  1.   

    先做需求分析吧,因为不是我的需求,所以可能情况考虑复杂了,先解释下上面正则的分析过程,再说下可能存在的优化。首先楼主要从源字符串整体中去掉一部分内容,那这种需求基本上可以确定为替换,也就是用Replace方法来处理了。接下来看一下要替换内容的复杂度,这里我可能考虑复杂了,我分析的结果是这样的
    1、存在于<td...>和</td>之间
    2、可以提取出公共规律的部分为<span...>...</span>
    3、符合条件2的子串可能有一个或多个
    这样的复杂度就不适合用一个正则直接替换了,所以想到用正则委托,但事实上这并不是正则委托典型的应用场景。使用委托可以把符合一定规律的子串先提取出来,做一定的处理后,再替换回子串所在的位置。因为是在委托方法内处理,所以可以做很多如运算等复杂的处理,而不仅仅是字符串的操作。这样分析之后,就要把符合规律的子串提取出来,以Match对象为参数传给委托方法处理。那就分析一下要提取子串的规律,来写下正则
    1、是一个<span...>...</span>子串,<span...>中包含onmouseover属性,且符合onmouseover="...('...','...'...)"这样的规律
    2、前面为<td...>和任意多个<span...>...</span>子串
    3、后面为任意多个<span...>...</span>子串和</td>分别写出对应的正则
    //1、是一个<span...>...</span>子串,<span...>中包含onmouseover属性,且符合onmouseover="...('...','...'...)"这样的规律
    \s*<span(?<values>[^>]*)>\s*(?<content>(?:(?!</?span\b).)*)(?<!\s)\s*</span>\s*
    //2、前面为<td...>和任意多个<span...>...</span>子串
    (?<=<td[^>]*>[^<]*(<span[^>]*>(?:(?!</?span\b).)*</span>\s*)*)
    //3、后面为任意多个<span...>...</span>子串和</td>
    (?=(<span[^>]*>(?:(?!</?span\b).)*</span>\s*)*</td>)提取出相应的子串后,就是在委托方法中进行一下处理,取出onmouseover属性的内容和<span...>和</span>之间的内容,并补充一些“,”、“~”之类的内容,再替换回子串所在的位置就可以了。
    当然,我上面可能考虑得过于复杂了,如果是所有带有onmouseover属性的<span...>都符合这一规律,完全可以一个正则搞定,可以试下这样是否符合要求
    Regex regSpan = new Regex(@"(?is)\s*<span(?:(?!onmouseover=).)*onmouseover=""[^,(]*\(\s*(?<value>[^"")>]*)\)""[^>]*>\s*(?<content>(?:(?!</?span\b).)*)(?<!\s)\s*</span>\s*");
    string result = regSpan.Replace(yourStr, "${value},${content}~");
    richTextBox2.Text = result;这里只是根据<span和onmouseover来进行替换,而没有考虑是否在<td...>和</td>之间。
      

  2.   

    学习中...
    1我用的工具是MTracer2.0 但我发现如果将正则放到哪里面,好像不能得到正确结果,需要用什么工具来测试呢,
    2我对正则中的前后连接效果十分不解,
    比如c#的语法;号就是一个句子终结,一般情况大多语句的执行规则是由左向右,但像这样复杂的正则,里面的 * . 这些匹配符它可以前后都使用,我无法把握如何对正则分割哪里,正则有块结束符吗或有什么规定来完成这种分割。》\s*<span(?<values>[^>]*)>\s*(?<content>(?:(?!</?span\b).)*)(?<!\s)\s*</span>\s*
    如上语句我看就就会出现这样困扰
    1、\s*<span(?<values>[^>]*)>\s*
    2、(?<content>(?:(?!</?span\b).)*)
    3、(?<!\s)\s*</span>\s*
    或这样
    1、\s*<span(?<values>[^>]*)>
    2、\s*(?<content>(?:(?!</?span\b).)*)(?<!\s)\s*
    3、</span>\s* 
      

  3.   

    1、正则测试工具我一直用的就是MTracer,虽然功能没有RegexBuddy那么强大,但好在简单、实用,除了平衡组无法匹配外,其它常见正则语法都支持
    RegexBuddy第一次用给我的结果就是错的,后来就懒得用了
    2、正则中没有类似的概念
    “?”、“*”、“+”、“{m,n}”等是量词
    如果前面没有用“()”限定范围,那它修饰的就是一个字符或是一个元字符。比如“a+”,表示一个以上的字符“a”,也就是可以匹配“a”,“aaa”,“aaaaaaaaa”等等;或者如“\s*”表示0个或任意多个空白字符
    如果前面用了“()”来限定范围,那么它修饰的就是“()”内的整体。比如“(abc)+”,表示一个以上的字符串“abc”,也就是可以匹配“abc”,“abcabc”,“abcabcabcabc”等等。\s* 表示任意多个空白字符
    (?<values>[^>]*) 是命名捕获组,语法(?<name>Expression)
    (?:Expression) 非捕获组
    (?!Exp)、(?=Exp)、(?<!Exp)、(?<=Exp) 都是环视以上这些语法规则在我的博客里都有介绍的
      

  4.   

    谢谢
    我想问一下,你写这个正则是用1 2 3 来增加的的顺序吗,能否对1 2 3 步再进行解分 分解到10步左右,让我理解一下如何变化的。
    引用前面代码
    //1、是一个<span...>...</span>子串,<span...>中包含onmouseover属性,且符合onmouseover="...('...','...'...)"这样的规律
    \s*<span(?<values>[^>]*)>\s*(?<content>(?:(?!</?span\b).)*)(?<!\s)\s*</span>\s*
    //2、前面为<td...>和任意多个<span...>...</span>子串
    (?<=<td[^>]*>[^<]*(<span[^>]*>(?:(?!</?span\b).)*</span>\s*)*)
    //3、后面为任意多个<span...>...</span>子串和</td>
    (?=(<span[^>]*>(?:(?!</?span\b).)*</span>\s*)*</td>)
      

  5.   

    怎么说呢,我写正则时当然不用分步来写,但肯定要有一个分析过程的
    首先是对需求的明确和分析,只有需求明确,才能确定究竟使用哪种方法处理、怎样处理才能达到最优
    需求分析,确定使用的方法后,才会进行具体的实现,也就是正则的书写
    具体实现时要找出字符串的规律,是否能过一个正则表达式实现,一个表达式是否合理,有时为了提高可读性、可扩展性和效率,可能需要把正则分成多个来写,注意,并不是一个正则实现的效率就一定比多个正则实现的效率高,要看场景和正则的复杂度就楼主的需求,首先确认是一个替换的需求,使用Replace方法,由于需要对替换的内容进行一些处理,所以需要用到委托方法
    字符串分析过程基本上就是由整到零,正则的书写过程基本上就是由零到整,我虽然不会去套用这样一种模式,而主要是在脑中分析和考虑,但也基本上可以认为是这样一个分析过程
    需要替换的是什么样的字符串,基本上就可以按这三条来总结规律:
    1、是一个 <span...>... </span>子串, <span...>中包含onmouseover属性,且符合onmouseover="...('...','...'...)"这样的规律 
    2、前面为 <td...>和任意多个 <span...>... </span>子串 
    3、后面为任意多个 <span...>... </span>子串和 </td> 
    各条之间基本上没有什么影响,就可以单独实现后组合一下
    其实这些分步正则也没什么好解释的,写的多了,自然就知道该采用什么样的语法了,说下第一条的分析和书写过程吧
    <span开头,前面可能有多个空白字符,就是
    \s*<span
    然后是任意多个不是“>”的字符,一直匹配到“>”为止,也就是<span...>标签,由于其中的内容需要在委托方法中做二次处理,所以用个捕获组来捕获
    (?<values>[^>]*)>
    然后就是<span...>和</span>之间的内容
    (?:(?!</?span\b).)* 因为<span...>和</span>之间不可以再出现“<span”和“</span”,所以这就表示任意一个从它开始,右侧不能是<span或</span的字符,这样的字符可以有任意多个
    用一个捕获组来捕获,就是
    (?<content>(?:(?!</?span\b).)*)
    因为它两侧可能出现空白字符,而这些空白字符在替换结果中是不需要的,所以不应包含在捕获组中,前面的\s*匹配的开头的空白字符,后面的(?<!\s)表示捕获组捕获内容最后不能是空白字符,也就是匹配到空白字符为止,而结尾的空白字符则由后面的\s*来匹配,也就是
    \s*(?<content>(?:(?!</?span\b).)*)(?<!\s)\s*
    接下来就是</span>和,后面还可能有空白字符,也就是
    </span>\s*
    合起来就是
    \s*<span(?<values>[^>]*)>\s*(?<content>(?:(?!</?span\b).)*)(?<!\s)\s*</span>\s*  其它两条和这个差不多,只是用到了环视的语法,这些语法在我的博客中都有讲解正则因为比较抽象,刚开始学的时候会有些不知道从哪里入手,多看一些,多动手练习一下,其实还是很容易掌握的
    楼主的这个需求我可以讲解的很详细,但是如果想真正理解,还是对基本的语法规则有所了解的,如果想真正掌握,还需要自己多动手去写
    我开始学正则时,基本上就是在论坛里先翻老帖子,看别人怎么写,然后有了新帖子,就试着自己动手去写,写得出就回一下帖,写不出就看别人是怎么写的,久而久之也就会了