用于多个表的PHP正则表达式


PHP regular expression for multiple tables

我需要帮助构建用于文本分隔的正则表达式。现在我有一些类似的文本

text text text
text text text
<div> text text text </div>
<table class="table1">
<tr>
<td>
</td>
</tr>
</table>
text text text
text text text
text text text
<table class="table2">
<tr>
<td>
</td>
</tr>
</table>
text text text
text text text
text text text

我需要创建一个正则表达式来分隔文本和表。现在我有了正则表达式

preg_match_all( "/(.*)(<table(?s).*?'/table>)(.*)/si", $value[ 'TEXT' ], $matches );

这个表达式适用于这样的文本

text text text
text text text
<div> text text text </div>
<table class="table1">
<tr>
<td>
</td>
</tr>
</table>

它与分离

text text text
text text text
<div> text text text </div>

    <table class="table1">
    <tr>
    <td>
    </td>
    </tr>
    </table>

但对于文本

text text text
text text text
<div> text text text </div>
<table class="table1">
<tr>
<td>
</td>
</tr>
</table>
text text text
text text text
text text text
<table class="table2">
<tr>
<td>
</td>
</tr>
</table>
text text text
text text text
text text text

我的正则表达式不起作用。它是带有的返回阵列

[0] =>"text text text
    text text text
    <div> text text text </div>
    <table class="table1">
    <tr>
    <td>
    </td>
    </tr>
    </table>
    text text text
    text text text
    text text text",
[1]=>"<table class="table2">
    <tr>
    <td>
    </td>
    </tr>
    </table>",
[2]=>"text text text
    text text text
    text text text"

如何构建正确的正则表达式?

它应该位于以下位置:

$doc = new DOMDocument;
$doc->loadHTML('html string');
$tables = $doc->getElementsByTagName('table');
foreach($tables as $table){
    $parent = $table->parentNode;
    $parent->removeChild($table);
}
$doc->normalizeDocument();
$text = array();
$xpath = new DOMXPath($doc);
$textnodes = $xpath->evaluate('//text()');
foreach($textnodes as $textnode){
    $text[] = $textnode->wholeText;
}
print_r($text)

这段代码加载html,查找和删除表,查找所有文本节点,并用它们的内容填充数组。您应该阅读更多关于PHPDOM的内容,以便根据您的需要对其进行微调。

去掉正则表达式开头和结尾的(.*)。唯一一次需要"填充"这样的regex是在使用类似Java的matches()方法时,该方法会自动在两端锚定匹配。

这里发生的情况是,第一个(.*)最初吞噬了整个文档,然后后退到足以让下一部分(<table等)匹配一个表元素的程度。然后,第二CCD_ 5消耗剩余的任何东西。这就解释了为什么preg_match_all()只捕获一个表元素,以及为什么它总是最后一个。

你也可以去掉(?s)。它并没有真正伤害任何东西,但它所做的只是打开single-line模式,并且您已经在最后使用s修饰符完成了这一操作。您可能想匹配一个空白字符(应该是's),但这会阻止它匹配<table>(即没有属性的表标记)。您应该使用'b(单词边界):

preg_match_all( '~<table'b.*?/table>~si', $value[ 'TEXT' ], $matches );

但是要注意,这种方法只适用于极其简单的HTML。即使在完全有效的HTML中,也有很多事情可以击败它(嵌套的表标记是最明显的例子)。

最好的解决方案是这个代码:

$test = preg_replace( "/<table(?s).*?'/table>/si", '<BREAKHERE>', $value[ 'TEXT' ] );
            $texts = explode( '<BREAKHERE>', $test );
            foreach ( $texts as $keyTEXT => $valueTEXT )
            {
                $TmpVal = str_replace( "'r", "", $valueTEXT );
                $TmpVal = str_replace( "'n", "", $TmpVal );
                $TmpVal = str_replace( "'r'n", "", $TmpVal );
                if ( trim( $TmpVal ) != '' )
                {
                    preg_match_all( "/'w/", $TmpVal, $mtchs );
                    if ( count( $mtchs[ 0 ] ) > 0 )
                    {
                        $value[ 'TEXT' ] = str_replace( $valueTEXT, ' <div class="panel-container">' . $valueTEXT . '</div>', $value[ 'TEXT' ] );
                    }
                }
            }