0

我尝试使用 php 将一些可怕的无效 html 代码映射到我以后需要的 xml 结构。这工作得很好,但总有一些我无法处理的部分。所以决定是,只删除该代码,以便 xml 保持有效。这就是它的样子。

<body>
    <item>abc</item>
    <item>def</item>
    unparsable rest
</body>

所以目标是找到一个解决方案(可能是正则表达式,但我愿意接受任何解决方案)来删除“无法解析的其余部分”。

我尝试在这个正则表达式中使用 preg_replace

/<\/item>(((?!item).)*)\s*<\/body>/iU

它工作得很好,完全匹配我想要在 $1 中拥有的部分,最后一个 和 之间的所有东西,但是由于 xmls 非常大,计算只是在几毫秒后崩溃。我知道正则表达式在做负前瞻方面不太好,但我不认为它那么糟糕。

所以需要一个更有效的解决方案。不幸的是,我不能使用 strrpos,因为在

4

2 回答 2

1

您的正则表达式模式中有一个经过调和的贪婪令牌。它本质上很慢,请参阅我链接到的答案中的“性能问题”部分。

因此,您当前的正则表达式(我更喜欢在不带U和带s修饰符 as的情况下编写)在 231 steps~</item>(((?!item).)*?)\s*?</body>~is匹配您的输入字符串

\s*注意和这里没有太大的语义差异,\s*?因为之前没有其他量化模式</body>\s*,贪婪模式,在这种情况下是首选。

让我们展开模式并替换((?!item).)*?[^i]*(?:i(?!tem)[^i]*)*. ~</item>([^i]*(?:i(?!tem)[^i]*)*)\s*</body>~is 在 117 步内匹配您的输入。

对于字符串来说,这仍然是相当多的。后面的空格</item>可以与所有格匹配,\s*+以减少对字符串该部分的回溯访问。显示~</item>\s*+([^i]*(?:i(?!tem)[^i]*)*)\s*</body>~is了改进,现在匹配字符串需要 89 步,并且仅unparsable rest落在第 1 组值中。

不幸的是,我们不能在这里玩太多回溯,因为您想从 Group 1 值中删除尾随空格。

如果您想匹配所有之间</item>且不</body>包含<item>内部的,则模式将如下所示~</item>\s*+([^<]*(?:<(?!item>)[^<]*)*)\s*</body>~is,请参阅正则表达式演示

于 2020-01-23T08:54:41.917 回答
0

检查每一行以 '<' 开始并以 '>' 结束:

$t ='<body>
    <item>abc</item>
    <item>def</item>
    unparsable rest
</body>';

// break the string into lines
$filtered = array_filter(explode("\n", $t), function($line) {
    // each line
    $line = trim($line); //ignore white spaces
    return $line[0] == '<' && substr($line, -1) == '>';
});
// rebuild the string
$result = implode("\n", $filtered);
echo $result;

演示:https ://3v4l.org/Mt5eG

于 2020-01-23T10:14:34.380 回答