我希望匹配表格中的特定表格。这是示例html和迄今为止失败尝试的摘要:
<table id="parent">
<table class="possible_target">
<tr><td>We're tageting this table</td></tr>
</table>
</table>
<table class="possible_target">
<tr><td>We're not targeteing this table</td></tr>
</table>
这是我最初的尝试。但即使它奏效了,它也可能与第二张未通过的表格相匹配:
~(?=<table.*?)<table class="possible_target".*?</table>~si
这是我对我想要完成的事情的sudo表达。在进行匹配之前,它会声明是否存在开始表标签以及没有关闭表标签:
~(?=<table.*?)(?!</table>)<table class="possible_target".*?</table>~si
答案 0 :(得分:2)
我发现这很有趣,因为使用正则表达式和嵌套的html标签很有挑战性。
我的尝试确实(应该)以下内容:
1。)使用回调函数按深度枚举表。最低深度= 1
// html stuff to process
$source = "your input";
// specify tag to match
$rx_tag = "table";
// match all $rx_tag in depth (lowest = 1)
$rx_depth = 2;
// ----------------------------
// set markers using callback function
$source = preg_replace_callback('~<(/)?'.$rx_tag.'~i','set_tag_depth',$source);
function set_tag_depth($out)
{
global $tag_depth;
if($out[1]=="/") {
$tag_depth--; return $out[0].($tag_depth+1);
}
$tag_depth++; return $out[0].$tag_depth;
}
#echo nl2br(htmlspecialchars($source));
2。)现在将表重命名为深度,例如对于<table2 ... </table2>
内的表格,<table1, <table3 ... </table3>
内的所有表格均为<table2
,依此类推。现在很容易匹配所需深度的表格。然后剥离枚举,以防再次需要原始源。
// get specified tags in desired depth
$pattern = '~<'.$rx_tag.(string)$rx_depth.'.*</'.$rx_tag.(string)$rx_depth.'>~Uis';
preg_match_all($pattern,$source,$out);
// strip markers
if(!empty($out[0]))
{
foreach($out[0] AS $v)
{
$v = preg_replace('~(</?'.$rx_tag.')\d+~i','\1',$v);
// test output
echo nl2br(htmlspecialchars($v))."<br>------------------------------<br>";
}
}
$source = preg_replace('~(</?'.$rx_tag.')\d+~i','\1',$source);
如果标签包含相同类型的标签,那么这些标签不会从父母标签中删除,例如<table2>...</table2
&GT;可能包含<table3>...</table3> ... <table3>...</table3>
。设置$rx_depth = 3;
以获取这些内容。
我希望它能够正常工作,已经非常疲惫了:-)它的设计适用于任何类型的标签,但没有进行太多测试。至少是一个想法。
答案 1 :(得分:1)
使用同名的父/兄弟标签搜索平衡文本的问题 仅在属性上有所不同。
也就是说,你可以一次性收集所有潜在的父母候选人平衡标签 然后在另一个通道中搜索“可能目标”的候选人。
需要2个几乎相同的正则表达式(仅按属性不同) 有关详细信息,请参阅扩展的正则表达式(底部)。
PHP示例代码
// PHP sample code
$html =
'
<table id="parent">
<table class="possible_target">
C table data
</table>
<table class="possible_target">
D table data
</table>
</table>
<table id="parent">
<table>
<table class="possible_target">
<tr><td>We\'re targeting this table</td></tr>
</table>
</table>
</table>
<table class="possible_target">
<tr><td>We\'re not targeteing this table</td></tr>
</table>
'
;
// Regexes -
$rx_Parent = '~(?s)<table\s+id="parent">((?<Table_Core>(?:(?>(?:(?!</table\s*>|<table[\s>][^>]*(?<!/)>).)*)|(?<New_Table><table(?!\s+id="parent">)[\s>][^>]*(?<!/)>(?&Table_Core)</table\s*>))*))</table\s*>~';
$rx_Target = '~(?s)<table\s+class="possible_target">((?<Table_Core>(?:(?>(?:(?!</table\s*>|<table[\s>][^>]*(?<!/)>).)*)|(?<New_Table><table(?!\s+class="possible_target">)[\s>][^>]*(?<!/)>(?&Table_Core)</table\s*>))*))</table\s*>~';
// Match all possible parent candidates -
if ( preg_match_all ( $rx_Parent, $html, $ParentMatches, PREG_PATTERN_ORDER ) )
{
print "\n============================\n";
print_r( $ParentMatches[0] );
print "\n\n";
foreach( $ParentMatches[0] as $parent )
{
// Match each individual parent candidate possible targets -
if ( preg_match_all ( $rx_Target, $parent, $TargetMatches, PREG_SET_ORDER ) )
{
print "\n-----------------\n>Found Valid Parent\n";
foreach( $TargetMatches as $target )
{
print "Target:\n'" . $target[0] . "'\n"; // group 0
print "Core = \n'" . $target[1] . "'\n"; // group 1
}
}
}
}
else
{
print "No parents\n";
}
输出&gt;&gt;
============================
Array
(
[0] => <table id="parent">
<table class="possible_target">
C table data
</table>
<table class="possible_target">
D table data
</table>
</table>
[1] => <table id="parent">
<table>
<table class="possible_target">
<tr><td>We're targeting this table</td></tr>
</table>
</table>
)
-----------------
>Found Valid Parent
Target:
'<table class="possible_target">
C table data
</table>'
Core =
'
C table data
'
Target:
'<table class="possible_target">
D table data
</table>'
Core =
'
D table data
'
-----------------
>Found Valid Parent
Target:
'<table class="possible_target">
<tr><td>We're targeting this table</td></tr>
</table>'
Core =
'
<tr><td>We're targeting this table</td></tr>
'
扩展正则表达式
# BalancedText_PHP_Html.rxf
# Processed by RegexFormat4 (http://www.regexformat.com)
# '~(?s)<table\s+id="parent">((?<Table_Core>(?:(?>(?:(?!</table\s*>|<table[\s>][^>]*(?<!/)>).)*)|(?<New_Table><table(?!\s+id="parent">)[\s>][^>]*(?<!/)>(?&Table_Core)</table\s*>))*))</table\s*>~'
(?s) # Dot-All
# Parent Table
# ==================
<table \s+ id="parent"> # Parent table start
( # (1 start), Core Start
(?<Table_Core> # (2 start), Table Core
(?:
(?>
(?:
(?! # Not start/end of another table
</table \s* >
|
<table [\s>] [^>]*
(?<! / )
>
)
.
)*
)
|
(?<New_Table> # (3 start), New Table
<table # Table start
(?! \s+ id="parent"> ) # but, not a parent table type
[\s>] [^>]*
(?<! / )
>
(?&Table_Core) # Recurse Table Core
</table \s* > # Table end
) # (3 end)
)*
) # (2 end)
) # (1 end), Core End
</table \s* > # Parent table end
# ==========================================================================
(?s) # Dot-All
# Target Table
# ==================
<table \s+ class="possible_target"> # Target table start
( # (1 start), Core Start
(?<Table_Core> # (2 start), Table Core
(?:
(?>
(?:
(?! # Not start/end of another table
</table \s* >
|
<table [\s>] [^>]*
(?<! / )
>
)
.
)*
)
|
(?<New_Table> # (3 start), New Table
<table # Table start
(?! \s+ class="possible_target"> ) # but, not a target table type
[\s>] [^>]*
(?<! / )
>
(?&Table_Core) # Recurse Table Core
</table \s* > # Table end
) # (3 end)
)*
) # (2 end)
) # (1 end), Core End
</table \s* > # Target table end