需求:就是通过id获得一个html标签块。要处理的字符串:
<html>
<body>
<div id="div1">
        <div id="div2" style="background:Red;">
                <div id="div3">
                        <table id="table1">
                                <tr>
                                        <td>
                                                <div id="div4" style="width:100p
x"></div>
                                        </td>
                                </tr>
                        </table>
                </div>
        </div>
        <div id="div5">
                <a href="http://www.csdn.net">csdn</a>
        </div>
</div>
<img src="http://www.csdn.net/Images/logo_csdn.gif"/>
</body>
</html>输入输出样例1
输入:"div1"
输出:
<div id="div1">
        <div id="div2" style="background:Red;">
                <div id="div3">
                        <table id="table1">
                                <tr>
                                        <td>
                                                <div id="div4" style="width:100p
x"></div>
                                        </td>
                                </tr>
                        </table>
                </div>
        </div>
        <div id="div5">
                <a href="http://www.csdn.net">csdn</a>
        </div>
</div>输入输出样例2
输入:"div2"
输出:
        <div id="div2" style="background:Red;">
                <div id="div3">
                        <table id="table1">
                                <tr>
                                        <td>
                                                <div id="div4" style="width:100p
x"></div>
                                        </td>
                                </tr>
                        </table>
                </div>
        </div>输入输出样例3
输入:"div3"
输出:
                <div id="div3">
                        <table id="table1">
                                <tr>
                                        <td>
                                                <div id="div4" style="width:100p
x"></div>
                                        </td>
                                </tr>
                        </table>
                </div>
输入输出样例4
输入:"table1"
输出:
                        <table id="table1">
                                <tr>
                                        <td>
                                                <div id="div4" style="width:100p
x"></div>
                                        </td>
                                </tr>
                        </table>调试代码:
目前只实现没有嵌套的匹配--"div4"
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string html = @"
<html>
<body>
<div id=""div1"">
<div id=""div2"" style=""background:Red;"">
<div id=""div3"">
<table id=""table1"">
<tr>
<td>
<div id=""div4"" style=""width:100px""></div>
</td>
</tr>
</table>
</div>
</div>
<div id=""div5"">
<a href=""http://www.csdn.net"">csdn</a>
</div>
</div>
<img src=""http://www.csdn.net/Images/logo_csdn.gif""/>
</body>
</html>";
            Console.WriteLine(html);
            string[] idList = { "div1", "div2", "div3", "div4", "table1" };            /* TODO : 这里发挥 */
            string pattern = @"<([a-z]+)[^>]*\bid=(""|'){0}\2[^>]*></\1>";             foreach (string id in idList)
            {
                Match match = Regex.Match(html, string.Format(pattern, id), 
                    RegexOptions.Singleline | RegexOptions.IgnoreCase);
                Console.WriteLine("--------begin {0}--------", id);
                if (match.Success)
                    Console.WriteLine(match.Value);
                else
                    Console.WriteLine("o(╯□╰)o");
                Console.WriteLine("--------end {0}--------", id);
            }
            Console.ReadKey();
        }
    }
}

解决方案 »

  1.   

    string pattern = @"(<([a-z]+)[^>]*\bid=(""|'){0}\3[^>]*>)(?<tag>).*(</\2>)(?<-tag>)";
      

  2.   

    这不就相当于是xml里面的,通过一个标签得到它里面的所有内容嘛!
    不知道理解的对不对,以后还请大家多多指教!
      

  3.   

    测试通过,嵌套的问题必须使用平衡组,但好像大部分的正则引擎都不支持平衡组的概念,不过 .NET 倒是可以。
      

  4.   


    document.getelementByid("asd").innerHTML不行吗或用jquery的 $(#fg).appen(..)
      

  5.   

    $("condition1").clone.appenTo( $("condition2") ); 将克隆后的标记添加到符合condition2的标记后。
      

  6.   

    呵呵,有点问题,那个 div4 中间没字符,直接闭合了,匹配不正确
      

  7.   

    清洁工大侠也研究正则?应该要用到平衡组。可能还要考虑这种情况: 
    <img id="img1" src="images/ok.gif" />并且 id='img1' 或 id=img1 ,在浏览器中似乎都能正常工作,如果也要考虑这些情形,就更麻烦了。
      

  8.   

    o(╯□╰)o 对正则还没有研究得这么深... 平衡组都没有听说过 - -要是我的话宁可自己分析标签,用stack来记录位置,顺便检查标签是否闭合
      

  9.   

    <br>  <hr>  写成 <br />  <hr /> 还好些,如果不写 /,就更不好判断闭合的情形了。
      

  10.   

    这个情况我也考虑到了,忘记把img放到div中。
      

  11.   

    MSDN相关资料:分组构造描述了正则表达式的子表达式,通常用于捕获输入字符串的子字符串。下表描述了正则表达式分组构造。分组构造
     说明
     
    ( 子表达式 ) 
     捕获匹配的子表达式(或非捕获组;有关更多信息,请参见正则表达式选项中的 ExplicitCapture 选项)。使用 () 的捕获基于左括号按顺序从 1 开始自动编号。捕获元素编号为零的第一个捕获是由整个正则表达式模式匹配的文本。
     
    (?< name > 子表达式)
     将匹配的子表达式捕获到一个组名称或编号名称中。用于 name 的字符串不得包含任何标点符号,并且不能以数字开头。可以使用单引号替代尖括号,例如 (?'name')。
     
    (?< name1 - name2 > 子表达式)
     (平衡组定义。) 删除先前定义的 name2 组的定义,并在 name1 组中存储先前定义的 name2 组和当前组之间的间隔。如果未定义 name2 组,则匹配将回溯。由于删除 name2 的最后一个定义会显示 name2 的先前定义,因此该构造允许将 name2 组的捕获堆栈用作计数器,用于跟踪嵌套构造(如括号)。在此构造中,name1 是可选的。可以使用单引号替代尖括号,例如 (?'name1-name2')。有关更多信息,请参见本主题中的示例。
     
    (?: 子表达式)
     (非捕获组。) 不捕获由子表达式匹配的子字符串。
     
    (?imnsx-imnsx: 子表达式)
     应用或禁用子表达式中指定的选项。例如,(?i-s: ) 将打开不区分大小写并禁用单行模式。有关更多信息,请参见正则表达式选项。
     
    (?= 子表达式)
     (零宽度正预测先行断言。) 仅当子表达式在此位置的右侧匹配时才继续匹配。例如,\w+(?=\d) 与后跟数字的单词匹配,而不与该数字匹配。此构造不会回溯。
     
    (?! 子表达式)
     (零宽度负预测先行断言。) 仅当子表达式不在此位置的右侧匹配时才继续匹配。例如,\b(?!un)\w+\b 与不以 un 开头的单词匹配。
     
    (?<= 子表达式)
     (零宽度正回顾后发断言。) 仅当子表达式在此位置的左侧匹配时才继续匹配。例如,(?<=19)99 与跟在 19 后面的 99 的实例匹配。此构造不会回溯。
     
    (?<! 子表达式)
     (零宽度负回顾后发断言。) 仅当子表达式不在此位置的左侧匹配时才继续匹配。
     
    (?> 子表达式)
     (非回溯子表达式(也称为“贪婪”子表达式)。) 该子表达式仅完全匹配一次,然后就不会逐段参与回溯了。(也就是说,该子表达式仅与可由该子表达式单独匹配的字符串匹配。)默认情况下,如果匹配未成功,回溯会搜索其他可能的匹配。如果已知无法成功回溯,可以使用非回溯子表达式避免不必要的搜索,从而提高性能。
     
      

  12.   

    终于搞定了,这次应该没错了,原来知道有平衡组,但没研究过,总是想当然,人还是太浮躁。这次借楼主的题认真学习了一下,也算是小有收获,谢谢楼主!string pattern = @"<([a-z]+)[^>]*\bid=(""|'){0}\2[^>]*>(?><\1[^>]*>(?<tag>)|</\1>(?<-tag>)|.)*?(?(tag)(?!))</\1>";
      

  13.   

    赞orain的代码~~~
    这类嵌套的问题应该说用平衡组来做是肯定的了,不过平衡组我也不熟,我觉得过客应该也可以解决
      

  14.   

    介个,伴水写不出这个正则,骗淫的吧orain 25楼的正则已基本上满足需求了,完善了一下,做了些优化
                string html = @"
    <html>
    <body>
    <div id=""div1"">
        <div id=""div2"" style=""background:Red;"">
            <div id=""div3"">
                <table id=""table1"">
                    <tr>
                        <td>
                            <div id=""div4"" style=""width:100px""></div>
                        </td>
                    </tr>
                </table>
            </div>
        </div>
        <div id=div5>
            <a href=""http://www.csdn.net"">csdn</a>
        </div>
    </div>
    <img src=""http://www.csdn.net/Images/logo_csdn.gif""/>
    </body>
    </html>";
                Console.WriteLine(html);
                string[] idList = { "div1", "div2", "div3", "div4", "table1", "div5", "abc(def" };            /* TODO : 这里发挥 */
                string pattern = @"<([a-z]+)(?:(?!id)[^<>])*id=([""']?){0}\2[^>]*>(?>(?<o><\1[^>]*>)|(?<-o></\1>)|(?:(?!</?\1).))*(?(o)(?!))</\1>";            foreach (string id in idList)
                {
                    Match match = Regex.Match(html, string.Format(pattern, Regex.Escape(id)),
                        RegexOptions.Singleline | RegexOptions.IgnoreCase);
                    Console.WriteLine("--------begin {0}--------", id);
                    if (match.Success)
                        Console.WriteLine(match.Value);
                    else
                        Console.WriteLine("o(╯□╰)o");
                    Console.WriteLine("--------end {0}--------", id);
                }
                Console.ReadLine();
      

  15.   

    完善一:增加了对以下标签类型的支持
            <div id=div5>
                    <a href="http://www.csdn.net">csdn</a>
            </div>改进一:效率上
    1、如果贪婪模式使用得法,会比非贪婪模式快很多,尤其是在数据源较大的情况下;而正则的效率瓶颈,以及效率陷阱,很多时候是由于非贪婪模式使用不当导致的
    2、经测试((?!exp).)exp会比[^char]*?exp或[^char]*exp效率高,应该是.NET的NFA引擎做了优化,其它语言中不敢保证改进二:容错性
    将id做了下预处理Regex.Escape(id)),否则输入的id为“abc(def”这类包含正则中需转义的字符时,会抛异常
                    Match match = Regex.Match(html, string.Format(pattern, Regex.Escape(id)),
                        RegexOptions.Singleline | RegexOptions.IgnoreCase);PS1:目前好像只有.NET支持平衡组和不定长的负向预搜索(?<=\d+)
    PS2:固化分组(?>exp)好像也是绝大部分语言所不支持的
      

  16.   

    在windows下开发桌面程序好像很少用到正则。
      

  17.   

    细节上优化了一下string pattern = @"<([a-z]+)(?:(?!\bid\b)[^<>])*id=([""']?){0}\2[^>]*>(?>(?<o>)<\1[^>]*>|(?<-o>)</\1>|(?!</?\1).)*(?(o)(?!))</\1>";如果考虑到效率和应用场景,可以尝试以下优化:
    1、在频繁调用的情况下,考虑使用RegexOptions.Compiled参数,预编译
    2、或者封装到assembly中
      

  18.   

    (?:(?!</?\1).) 这个分支的修改很妙,当时我一直想在这个分支中把前两个标签过滤掉,但没找到恰当的方法,无奈才用了非贪婪的匹配。
    受教了,谢谢 lxcnn。
      

  19.   


    客客改进的正则很不错,建议把红色部分改为:
    (?!\bid\b)否则对以下html串,因为width中含有id,会造成匹配不到:
    <div style='width:100px' id='div4'></div>
      

  20.   


    建议把红色的部分改为:
    ""[^""]*""|'[^']*'|[^""'<>]否则对以下html串,因为onclick的引号中含有<,会造成匹配不到: 
    <div onclick='if(x<5){return true}' id='div4'></div>
      

  21.   

    过客的正则研究得深,,,
    还没用过Regex.Escape()方法,又学到了。感谢大家参与和完善实现细节。
      

  22.   

    用:document.getElementById("id").outerHTML 不就行了吗
      

  23.   


    建议在 = 的前后加上 \s*:
    string pattern = @"<([a-z]+)(?:(?!\bid\b)""[^""]*""|'[^']*'|[^""'<>])*id\s*=\s*([""']?){0}\2[^>]*>(?>(?<o>)<\1[^>]*>|(?<-o>)</\1>|(?!</?\1).)*(?(o)(?!))</\1>";因为 <div id = 'div4'> 也是合乎规范的。
      

  24.   

    还要考虑这种情形:
    <div id='div4' onclick="if(x>5){print('</div>')}"></div>越来越复杂了:
    string pattern0 = @"<([a-z]+)(?:(?!\bid\b)_)*id\s*=\s*([""']?){0}\2_*>(?>(?<o>)<\1_*>|(?<-o>)</\1>|(?!</?\1).)*(?(o)(?!))</\1>";
    string pattern  = pattern0.Replace("_", @"(?:""[^""]*""|'[^']*'|[^""'<>])");
      

  25.   

    <img id='img1' src='ok.gif' />
    另外,这个正则也无法匹配上面的 img1
      

  26.   


    感觉这个需求用jquery真好的。
      

  27.   

    string pattern = @"( <([a-z]+)[^>]*\bid=(""|'){0}\3[^>]*>)(? <tag>).*( </\2>)(? <-tag>)";
      

  28.   

    嵌套的问题确实不适合用正则去解,其实如果对性能要求过高的话,正则都是不合适的,在大多数情形下,正则的性能是比较差的。不过楼主这个问题对于学习正则来说是很典型的,涉及到许多正则当中少见但却是功能强大的地方。在这里斗胆将上面的正则表达式注释一下,希望对不熟悉正则的兄弟能够有所帮助。
    <                    
    ([a-z]+)       (?# 匹配标签名称,若整个表达式匹配成功,会自动编组为 1。但这里仍然有疏漏,无法匹配类似于 h3 之类的标签)
    [^>]*                (?# 匹配标签和 id 间的任意字符)
    id=
    ([""']?)             (?# 匹配双/单引号或空,注意,在正则中,空也可以看作一项匹配,单纯的空匹配总会成功。若整个表达式匹配成功,编组为 2。)
    {0}                  (?# 这个值在楼主的程序中会被具体的 id 名称代替)
    \2           (?# 反向引用分组 2)
    [^>]*>         (?# 匹配剩余的字符及尖括号)
    (?>                  (?# 这是一个固化分组,表示本括号内后续的字符若匹配到了就不释放,以阻止回溯,可以提高效率)
    (?<o>)               (?# 空匹配,指定分组为 o。在这里的意思就是若发现后续的字符为分组 1 指定的标签,则压入一个位置进入堆栈,平衡组的开始)
    <\1[^>]*>       (?# 匹配分组 1 类型的标签)
    |
    (?<-o>)              (?# 平衡组出栈。在这里就是若发现后续的字符为分组 1 指定标签的闭合标签,则弹出最后入栈的分组 o)
    </\1>                (?# 匹配分组 1 指定标签的闭合标签)
    |
    (?!</?\1).           (?# 否定预查,匹配不属于分组 1 指定标签及其闭合标签中的任意字符,同时匹配标签和闭合标签是通过 /? 来达成的)
    )*           (?# 注意这个 * 号是针对整个括号的,所以它的作用范围是括号中的三个分支,这个括号的开头是一个固化分组)
    (?(o)(?!))      (?# 这是一个条件测试,完整的形式形如 (?(group)(exp1)|(exp2)),或 group 匹配成功,则执行 exp1,否则执行 exp2)
                         (?# 因为 o 是一个平衡组,有入栈和出栈,若 o 全部出栈或根本未匹配到 o,则 (o) 为 false,正则引擎会继续匹配后续的表达式,即下面的 </\1>。若 o 未全部出栈,则 (o) 为 true,正则引擎会执行表达式 (?!),(?!) 总会导致匹配失败(因为空匹配总会成功,而对总会成功的匹配取反,则总会失败),从而导致正则引擎回溯,不去匹配最后的 </\1>。)
    </\1>                (?# 匹配分组 1 指定标签的闭合标签)呵呵,个人的理解,有不当之外,敬请指正。
    另外,个人认为正则的匹配能刚好达到要求最好,一是可以避免太复杂的表达式,难以看懂,二是效率问题。
      

  29.   

    我觉得题目本身有问题问题在于不恰当的抽象。正则是通过规则来处理字符串html代码、标签块,这已经是比字符串高一个级别的抽象了。在字符串的级别,手动的以字符串的特征来识别和处理html标签块,这显然是很不划算的。