【问题标题】:How to use Perl Regex to detect <p> inside another <p>如何使用 Perl Regex 在另一个 <p> 中检测 <p>
【发布时间】:2011-06-29 18:55:53
【问题描述】:

我正在尝试解析“错误的 html”以使用 perl 正则表达式修复它。 错误的html如下:&lt;p&gt;foo&lt;p&gt;bar&lt;/p&gt;foo&lt;/p&gt;

我希望 perl 正则表达式返回给我:&lt;p&gt;foo&lt;p&gt;

我试过类似:'|(&lt;p\b[^&gt;]*&gt;(?!&lt;/p&gt;)*?&lt;p[^&gt;]*&gt;)|' 没有成功,因为我不能重复(?!&lt;/p&gt;)*?

Perl 正则表达式中是否有办法说出除以下序列之外的所有字符(在我的情况下为 &lt;/p&gt;

【问题讨论】:

标签: regex perl html-parsing


【解决方案1】:

尝试类似:

<p>(?:(?!</?p>).)*</p>(?!(?:(?!</?p>).)*(<p>|$))

快速分解:

<p>(?:(?!</?p>).)*</p>

匹配包含&lt;p&gt;&lt;/p&gt;&lt;p&gt; ... &lt;/p&gt;。部分:

(?!(?:(?!</?p>).)*(<p>|$))

在向前看时为“真” ((?! ... )) 没有 &lt;p&gt; 或输入的结尾 ((&lt;p&gt;|$)),没有任何 &lt;p&gt;&lt;/p&gt; 介于两者之间 ((?:(?!&lt;/?p&gt;).)*)。

演示:

my $txt="<p>aaa aa a</p> <p>foo <p>bar</p> foo</p> <p> bb <p>x</p> bb</p>";
while($txt =~ m/(<p>(?:(?!<\/?p>).)*<\/p>)(?!(?:(?!<\/?p>).)*(<p>|$))/g) {
  print "Found: $1\n";
}

打印:

Found: <p>bar</p>
Found: <p>x</p>

请注意,此正则表达式技巧仅适用于字符串中的&lt;p&gt;baz&lt;/p&gt;

<p>foo <p>bar</p> <p>baz</p> foo</p>

&lt;p&gt;bar&lt;/p&gt; 不匹配!替换 &lt;p&gt;baz&lt;/p&gt; 后,您可以对输入进行第二次运行,在这种情况下,&lt;p&gt;bar&lt;/p&gt; 将被匹配。

【讨论】:

  • 感谢您的快速帮助 :) 根据您的解决方案,我也尝试过:|(&lt;p\b[^&gt;]*&gt;(?:(?!&lt;/p&gt;).)*&lt;p[^&gt;]*&gt;)| 似乎工作正常,我应该使用您的解决方案有什么问题吗?
  • @Tumpap,但匹配您的字符串 &lt;p&gt;foo&lt;p&gt; 中的 &lt;p&gt;foo&lt;p&gt;bar&lt;/p&gt;foo&lt;/p&gt;...
【解决方案2】:

我同意安迪的观点。用正则表达式解析非平凡的 HTML 是一个痛苦的世界。

仔细查看 HTML::TreeBuilder::XPath 和 HTML::DOM 以对 HTML 文档进行结构更改。

【讨论】:

  • 看起来 DOM 和 TreeBuilder 在解析 HTML 时都“更正”了您的 HTML。这可能是也可能不是你想要的。
【解决方案3】:

这个正则表达式:

<p>(?:(?!</p>).)*?<p>

当匹配时

<p>foo<p>bar</p>foo</p>

结果

<p>foo<p>

【讨论】:

    【解决方案4】:

    如果您尝试验证 HTML,请考虑使用 HTML::TidyHTML::Lint 之类的模块。

    【讨论】:

      【解决方案5】:

      也许Marpa::HTML 会帮助你。在author's blog about it 上阅读一些有趣的功能。简而言之,解析器与解释器一起工作(我可能得到了一些不正确的语义),以根据代码中某个逻辑位置上可能出现的内容来确定应该出现的内容。

      其中显示的示例解决了类似的问题,因为您似乎以比使用正则表达式更一致的方式处理,这将不可避免地受到边缘情况的影响。

      Marpa::HTML 带有一个命令行实用程序,使用模块构建,称为html_fmt。这实现了一个解析引擎来修复和漂亮打印 html。这是一个例子。如果 'bad.html' 包含 &lt;p&gt;foo&lt;p&gt;bar&lt;/p&gt;foo&lt;/p&gt;html_fmt bad.html 给出:

      <!-- Following start tag is replacement for a missing one -->
      <html>
        <!-- Following start tag is replacement for a missing one -->
        <head>
        </head>
        <!-- Preceding end tag is replacement for a missing one -->
        <!-- Following start tag is replacement for a missing one -->
        <body>
          <p>
            foo
          </p>
          <!-- Preceding end tag is replacement for a missing one -->
          <p>
            bar
          </p>
          foo
          <!-- Next line is cruft -->
          </p>
        </body>
        <!-- Preceding end tag is replacement for a missing one -->
      </html>
      <!-- Preceding end tag is replacement for a missing one -->
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-10-17
        • 2018-09-15
        • 2015-08-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多