正则表达式提取不包含HTML块标记的行

时间:2009-07-25 22:51:51

标签: php regex

我正在寻找一个正则表达式来提取不包含HTML 块标记的所有相邻行,但它们可以包含HTML 内嵌标记

例如,如果我有以下文字......

bla bla bla bla
bla <code>bla bla</code> bla
bla bla bla bla
<img src="" alt="" />
bla bla bla bla
<div> bla bla bla
bla bla bla

...我想只提取以下几行......

bla bla bla bla
bla <code>bla bla</code> bla
bla bla bla bla
<img src="" alt="" />
bla bla bla bla

这可以用正则表达式吗?

更新:我正在使用PHP,我还有一个包含这些块标记名称的变量。 块标记是开放标记还是封闭标记无关紧要。

$blockTags = "h1|h2|h3|h4|h5|h6|hr|ol|ul|li|pre|blockquote|p|table|tr|td|div";

3 个答案:

答案 0 :(得分:2)

停止寻找。您的任务需要一个能够理解HTML标签何时打开和关闭的解析器,这是经典正则表达式无法做到的。

现代正则表达式可能能够实现这样的技巧,但你将构建世界上见过的最难以理解的正则表达式(好吧,不完全,但接近),如果你需要改变行为,你可能最终会重写整个事情。所以写一个相对简单的解析器来为你做,并且不要花费数小时试图编写一些其他人稍后会花费数小时试图理解的正则表达式。

顺便说一句,如果你问一个正则表达式问题,请指明你正在使用的语言。它们在不同语言中的工作方式略有不同。

答案 1 :(得分:1)

嗯,你可以做的是,你可以先过滤那些不包含任何html标签的行

[^<>]*

然后检查该行是否有任何html内联标记:

<(/?)(code|img|...)(/?)>

剩下的应该包含块标签 不过,不知道这对你来说是否足够准确。

答案 2 :(得分:1)

这不是“只有一个正则表达式”,但考虑到输入字符串在$str中,它应该完成工作:

$lines = explode(PHP_EOL, $str);
$linesToKeep = array();

foreach ($lines as $line) {
    if (!preg_match('#</?(' . $blockTags . ')>#', $line)) {
        $linesToKeep[] = $line;
    }
}

// Et voila ;-)
$strOK = implode(PHP_EOL, $linesToKeep);
var_dump($strOK);

用几句话说:

  • 它会使字符串爆炸以在线工作(因为您希望逐行保留或拒绝)。
  • 它逐行循环
  • 如果该行不包含<TAG></TAG>,则会将其放入$linesToKeep数组
  • 最后,输出字符串是根据该数组中的内容构建的

可能有更短的方法可以做,但是...但是那个很容易理解,我猜(不是某种“正则表达式地狱”或任何人无法维持的^^)

编辑:当我重新阅读OP时,我注意到排除了最后一行,而不是我的代码......如果你想要排除一个带有开始标记的行,以及紧接着它的行,这是另一个主张:

$lines = explode(PHP_EOL, $str);
$linesToKeep = array();
$i = 0;
$numLines = count($lines);

for ($i=0 ; $i<$numLines ; $i++) {
    $line = $lines[$i];
    if (!preg_match('#</?(' . $blockTags . ')>#', $line)) {
        $linesToKeep[] = $line;
    } else {
        if (preg_match('#<(' . $blockTags . ')>#', $line)) {
            // Opening tag, skip next line too ?
            $i++;
        }
    }
}

$strOK = implode(PHP_EOL, $linesToKeep);
var_dump($strOK);

如果你想在结束标记之前跳过行,你可以在我放$i++的地方做到这一点 - 但是它变得越来越难以阅读/理解^^ (和“解析”HTML如果你想要复杂的东西,那副手可能不是一个好主意^^)