我正在尝试使用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
关于我失败的地方的任何指示?
答案 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),或者可以轻松适应新情况。