匹配对标记与正则表达式

时间:2009-11-07 12:08:43

标签: regex html-parsing

我正在尝试使用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

关于我失败的地方的任何指示?

5 个答案:

答案 0 :(得分:6)

......答案总是一样的:HTML + regex cannot be done。抱歉。为您的特定框架使用HTML解析库。或者,如果保证您的文档仅包含有效的XHTML,请在评论中采用抖动建议的XPath方法。

答案 1 :(得分:3)

这可能会有所帮助 我在http://www.regular-expressions.info/examples.html找到了教程 提到捕获在给定文本中重复出现的字符串对。 建议是用吗?在。*之后,在文本

中首次出现该对的结束字符串后停止

答案 2 :(得分:1)

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

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

答案 3 :(得分:0)

感谢@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>

)

答案 4 :(得分:-1)

解析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";
}

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

如果您不使用递归(与(?2)+对齐),您将卡在such examples上。此代码可以处理所有这些代码(请先查看here),或者可以轻松适应新情况。