【问题标题】:Matching pair tag with regex使用正则表达式匹配对标记
【发布时间】:2010-12-14 03:37:21
【问题描述】:

我正在尝试从 xhtml 文档中检索特定标签及其内容,但它匹配错误的结束标签。

在以下内容中:

<cache_namespace name="content">
    <content_block id="15">
    some content here

        <cache_namespace name="user">
            <content_block id="welcome">
            Welcome Apikot!
            </content_block>
        </cache_namespace>
    </content_block>
</cache_namespace>

id="welcome" 的 content_block 结束标记实际上匹配为第一个开始 content_block 标记的结束标记。

我使用的正则表达式是:

/<content_block id="(.*)">([\w\W]*?)<\/content_block>/i

关于我在哪里失败的任何指示?

【问题讨论】:

标签: regex html-parsing


【解决方案1】:

……答案总是一样的:HTML + regex cannot be done。对不起。为您的特定框架使用 HTML 解析库。或者,如果您的文档保证只包含有效的 XHTML,请采用 jitter 在评论中提出的 XPath 方法。

【讨论】:

  • 我正要回答同样的问题。想知道这个问题已经被问过多少次了。以及是否应将此类问题标记为重复。
  • 谢谢。我一直专注于让它发挥作用,以至于我完全意识到它可能不起作用。
  • 根据您在那里使用的语言/正则表达式风格,您可能可以使用“递归表达式”来破解它。但实际上,确实,正则表达式完全是解析 HTML 的错误工具。
  • @bobince:是的。但这仍然假设有效的 XML,不幸的是,这对于大多数 HTML 来说有点牵强。对于 HTML,唯一可行的方法就是将文档真正转换为某种 DOM,然后对其进行操作。
【解决方案2】:

这可能会有所帮助 我在http://www.regular-expressions.info/examples.html 上找到了教程 其中提到捕获给定文本中重复出现的一对字符串。 建议是使用? after .* 使其在文本中第一次出现该对的结束字符串后停止

【讨论】:

    【解决方案3】:

    这是正则表达式的一个已知问题 - 您无法匹配对。匹配要么是贪婪的,它匹配它找到的最后一个,要么是非贪婪的,它匹配第一个。您无法说服正则表达式计算左括号和右括号。

    我建议将其加载到 DOM 中并使用它。如果您尝试实现 HTML 解析器,我建议您使用正则表达式对其进行词法分析,然后使用左右解析器来解析词法分析器的输出。

    【讨论】:

      【解决方案4】:

      感谢@Jan Żankowski@ikegami,他们的回答给了我灵感

      让我用PHP来演示代码

      <?php
      $xml = <<<EOT
      <cache_namespace name="content">
          <content_block id="15">
          some content here
      
              <cache_namespace name="user">
                  <content_block id="welcome">
                  Welcome Apikot!
                  </content_block>
              </cache_namespace>
          </content_block>
      </cache_namespace>
      EOT;
      
      preg_match('/<cache_namespace[^>]+>((?:(?!(<\/?div>)).)*)<\/cache_namespace>/s', $xml, $matches);
      print_r($matches);
      

      正则表达式注释

      • s 选项:模式中的 . 匹配所有字符,包括换行符
      • 这里的关键是(?:(?!STRING).)* 是字符串,就像[^CHAR]* 是字符

      结果

      Array
      (
          [0] => <cache_namespace name="content">
          <content_block id="15">
          some content here
      
              <cache_namespace name="user">
                  <content_block id="welcome">
                  Welcome Apikot!
                  </content_block>
              </cache_namespace>
          </content_block>
      </cache_namespace>
          [1] => 
          <content_block id="15">
          some content here
      
              <cache_namespace name="user">
                  <content_block id="welcome">
                  Welcome Apikot!
                  </content_block>
              </cache_namespace>
          </content_block>
      
      )
      

      【讨论】:

        【解决方案5】:

        解析 XHTML 或 XML 并不难。我假设您的代码有效或格式正确。

        #!/usr/bin/perl
        use strict;
        use warnings;
        use v5.10;
        my $xml = <<"EOF";
        <cache_namespace name="content">
            <content_block id="15">
            some content here
        
                <cache_namespace name="user">
                    <content_block id="welcome">
                    Welcome Apikot!
                    </content_block>
                </cache_namespace>
            </content_block>
        </cache_namespace>
        EOF
        
        while ($xml =~ m!
        <(content_block)\sid="welcome"> # Start tag definition.
         (\s*                           # It may consists of
           (?: <\!--.*?-->              # - comment
           |  [^<]*                     # - text
           |  <[^>]+/>                  # - another closed tag
           |  <\s*(\w+)[^>]*>           # - another tag with some content
               (?2)+                    # (recursive definition of possible tag content)
              </\3>
           )
         )*
        </\1>
        !sxgc) {
            print "==> $&\n\n";
        }
        

        请修改其他内容的开始标签定义(如&lt;\s*(\w+)[^&gt;]*+&gt;)。无论如何,这是一个很好的起点。

        如果您不使用递归(与(?2)+ 一致),您将停留在such examples。这段代码可以处理所有这些(请看here之前)或者可以轻松适应新情况。

        【讨论】:

        • 如果 content_block 和 id 之间有额外的空格,content_block 和 id 之间有一个属性,或者 id 之后有一个属性,则中断。如果添加 则会挂起(仅需要在属性值中编码
        猜你喜欢
        • 1970-01-01
        • 2013-11-18
        • 2018-09-01
        • 2012-04-02
        • 2013-11-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多