多个表的PHP正则表达式

时间:2012-09-10 08:21:22

标签: php regex preg-match-all

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

这样的文字
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"

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

3 个答案:

答案 0 :(得分:1)

它应该在某个地方:

$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,查找和删除表,查找所有文本节点并使用其内容填充数组。您应该阅读有关PHP DOM的更多信息,以便根据您的需要进行微调。

答案 1 :(得分:0)

在正则表达式的开头和结尾摆脱(.*)。你必须“填充”这样的正则表达式的唯一一次就是当你使用像Java的matches()方法那样自动锚定两端的匹配时。

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

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

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

但请注意,此方法仅适用于非常简单的HTML。即使在完全有效的HTML中,也有很多东西可以打败它(嵌套表标签是最明显的例子)。

答案 2 :(得分:0)

最佳解决方案是此代码:

$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' ] );
                    }
                }
            }