删除 Regex.Match 字符串的部分

3

我有一个HTML表格字符串。这个HTML大部分来自FrontPage,因此格式大多不佳。以下是一个快速示例。

<b>Table 1</b>
  <table class='class1'>
  <tr>
    <td>
      <p>Procedure Name</td>
    <td>
        <p>Procedure</td>
    </tr>
  </table>
<p><b>Table 2</b></p>
  <table class='class2'>
    <tr>
      <td>
        <p>Procedure Name</td>
        <td>
        <p>Procedure</td>
    </tr>
  </table>
<p> Some text is here</p>

据我所知,FrontPage会自动在每个新单元格中添加一个<p>标记。
我想删除表格内部的那些<p>标记,但保留表格外部的标记。到目前为止,我尝试了两种方法:
第一种方法是使用单个正则表达式来捕获表格中的每个<p>标记,然后使用Regex.Replace()将其删除。然而,我从未成功地得到正确的正则表达式。(我知道用正则表达式解析HTML很糟糕。我认为数据足够简单,可以应用正则表达式来处理它)。
我可以使用这个正则表达式轻松获取每个表格中的所有内容:<table.*?>(.*?)</table> 然后我想只获取<p>标记,于是我写了这个: (?<=<table.*?>)(<p>)(?=</table>)。但是这并没有匹配到任何内容。(显然,.NET允许在回溯中使用量词。至少在使用http://regexhero.net/tester/时给我的印象是这样的)
有什么办法可以修改这个正则表达式以仅捕获我需要的内容吗?
第二种方法是将表格内容仅捕获到一个字符串中,然后使用String.Replace()删除<p>标记。我正在使用以下代码来捕获匹配项:
MatchCollection tablematch = Regex.Matches(htmlSource, @"<table.*?>(.*?)</table>", RegexOptions.Singleline);

htmlSource 是一个包含整个HTML页面的字符串,这个变量将在处理后发送回客户端。我只想从 htmlSource 中删除我需要删除的内容。

我如何使用MatchCollection来删除 <p> 标记,然后将更新后的表格发送回 htmlSource

谢谢


2
通常认为使用正则表达式来解析HTML是不好的做法,但是Frontpage生成的HTML?那是一个全新的层次... - James Thorpe
@JamesThorpe 我猜 HTML 解析器无法读取这样的无效 HTML,所以可能没有其他选项。 - Alex Zhukovskiy
@Alex 一个解析器处理这个东西的机会比正则表达式可能永远不会被认为更好...而且,我没有看到 OP 发布的内容有什么明显的无效之处? - James Thorpe
@JamesThorpe 我同意在大多数情况下解析器是最佳选择,但一般的解析器在这种情况下只会抛出异常。 - Alex Zhukovskiy
你可以使用 MatchCollection 来查找所有内部的 <p> 标签,但是替换它们可能无法通过这种方式完成。 - user557597
3个回答

1
这个答案基于第二种建议的方法。将正则表达式更改为匹配表格内的所有内容:

<table.*?table>

使用Regex.Replace并指定MatchEvaluator来实现所需的替换:
Regex myRegex = new Regex(@"<table.*?table>", RegexOptions.Singleline);
string replaced = myRegex.Replace(htmlSource, m=> m.Value.Replace("<p>",""));
Console.WriteLine(replaced);

使用问题输入输出:

<b>Table 1</b>
    <table class='class1'>
    <tr>
    <td>
        Procedure Name</td>
    <td>
        Procedure</td>
    </tr>
    </table>
<p><b>Table 2</b></p>
    <table class='class2'>
    <tr>
        <td>
        Procedure Name</td>
        <td>
        Procedure</td>
    </tr>
    </table>
<p> Some text is here</p>

1
我想通过使用委托(回调)来实现。
string html = @"
<b>Table 1</b>
  <table class='class1'>
  <tr>
    <td>
      <p>Procedure Name</td>
    <td>
        <p>Procedure</td>
    </tr>
  </table>
<p><b>Table 2</b></p>
  <table class='class2'>
    <tr>
      <td>
        <p>Procedure Name</td>
        <td>
        <p>Procedure</td>
    </tr>
  </table>
<p> Some text is here</p>
";

Regex RxTable = new Regex( @"(?s)(<table[^>]*>)(.+?)(</table\s*>)" );
Regex RxP = new Regex( @"<p>" );

string htmlNew = RxTable.Replace( 
    html,
    delegate(Match match)
    {
       return match.Groups[1].Value + RxP.Replace(match.Groups[2].Value, "") + match.Groups[3].Value;
    }
);
Console.WriteLine( htmlNew );

输出:
<b>Table 1</b>
  <table class='class1'>
  <tr>
    <td>
      Procedure Name</td>
    <td>
        Procedure</td>
    </tr>
  </table>
<p><b>Table 2</b></p>
  <table class='class2'>
    <tr>
      <td>
        Procedure Name</td>
        <td>
        Procedure</td>
    </tr>
  </table>
<p> Some text is here</p>

0
通常情况下,正则表达式允许您处理嵌套结构,但它非常丑陋,应该避免使用。但如果你没有其他选择,你可以使用它。
static void Main()
{
    string s = 
@"A()
{
    for()
    {
    }
    do
    {
    }
}
B()
{
    for()
    {
    }   
}
C()
{
    for()
    {
        for()
        {
        }
    }   
}";

    var r = new Regex(@"  
                      {                       
                          (                 
                              [^{}]           # everything except braces { }   
                              |
                              (?<open>  { )   # if { then push
                              |
                              (?<-open> } )   # if } then pop
                          )+
                          (?(open)(?!))       # true if stack is empty
                      }                                                                  

                    ", RegexOptions.IgnorePatternWhitespace | RegexOptions.ExplicitCapture);

    int counter = 0;

    foreach (Match m in r.Matches(s))
        Console.WriteLine("Outer block #{0}\r\n{1}", ++counter, m.Value);

    Console.Read();
}

正则表达式“知道”块的起始位置和结束位置,因此您可以使用此信息来删除<p>标签,如果它没有适当的关闭标签。


我的主要问题不在于处理没有匹配关闭标签的<p>标签,因为我只想删除它们,即使它们有匹配的关闭标签。我的问题是我无法匹配或仅删除表格内部的标签。无论它们是否有匹配的关闭标签。 - Joeh Perron

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接