匹配对标记与正则表达式

问题描述 投票:2回答:5

我正在尝试从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
5个回答
6
投票

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


3
投票

这可能有助于我找到关于http://www.regular-expressions.info/examples.html的教程,该教程提到捕获在给定文本中重复出现的字符串。建议是用吗?在。*之后使其在文本中首次出现该对的结束字符串后停止


1
投票

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

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


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>

)

-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)或者可以轻松适应新情况。

© www.soinside.com 2019 - 2024. All rights reserved.