从HTML源代码中删除所有换行符

40

我知道混淆代码不是一个好主意。但我想让我的所有HTML代码都在一行中显示。所有的HTML标签都是通过PHP生成的,所以我认为这是可能的。我知道可以使用正则表达式将 \n\r 替换掉,但不知道该怎么做。如果我说得不够清楚,下面是一个例子:

$output = '<p>
              <div class="title">Hello</div>
           </p>';
echo $output;

在源代码查看器中查看为 <p><div class="title">Hello</div></p>


3
我想知道这是否可能。请不要告诉我这是浪费时间、不好的方法、毫无意义,因为我已经知道了,但我真的想尝试一下。 - mrN
4
那么我想你需要替换所有的\n\r\t 和空格。 - acm
1
你这样做是为了混淆你的HTML源代码还是为了压缩? - Blorgbeard
3
如果标记包含期望其内容为 whitespace:pre 的元素,应该怎么办? - Gordon
那我猜我会问另一个问题。哈哈……@Gordon,你能建议我一个更好的方法来保留pre标签内的空格吗? - mrN
1
@mrNepal 鉴于 whitespace:pre 是 CSS 声明,除了是 <pre><code> 的默认呈现模式之外,我认为没有好的解决方案。如果您想节省带宽并且每天不提供数百万个页面,则可能通过在 Web 服务器上进行 gzip 压缩来节省足够的带宽。 - Gordon
9个回答

47
也许是这个吗?
$output = str_replace(array("\r\n", "\r"), "\n", $output);
$lines = explode("\n", $output);
$new_lines = array();

foreach ($lines as $i => $line) {
    if(!empty($line))
        $new_lines[] = trim($line);
}
echo implode($new_lines);

4
trim 只删除开头和结尾的空格,行中间的空格不会被删除。 - Flo
谢谢,这个也非常有效。我应该用 preg 解决方案还是这个? - mrN
3
我会说这个更快、更可靠。 - seriousdev
2
你没有移除 '/n' 字符。需要使用 str_replace(array("\r\n", "\r", "\n"), "", $output) 函数。 - RayLoveless
4
@RayL,你误解了这段代码。\n 对于 explode() 是必需的。 - mgutt

37

也许你可以尝试这个。

// Before any output
ob_start();

// End of file
$output = ob_get_clean();
echo preg_replace('/^\s+|\n|\r|\s+$/m', '', $output);

除非我弄错了正则表达式,否则这应该可以捕获所有输出,并替换掉所有换行字符以及每行开头和结尾的所有空格。

如果您已经将所有输出收集到一个变量中,则可以直接使用最后一行,跳过输出缓冲区处理部分 :)


如果他在代码中使用了输出变量,那么就不需要捕获输出。 - Flo
哇,这是非常干净的解决方案。谢谢。 - mrN
对我来说,问题是这会删除换行之间的所有空格。这可能是无意的,比如 <span>\r\n<span> 变成了 <span><span>,它们的渲染方式与正常空格不同。使用简单的规则 preg_replace('/\s+/', ' ', $str) 将所有空白字符压缩为单个空格,并且不会引起冲突。 - Ciantic
1
我认为更好的 preg_replace('/^\s+|\n|\r|\t|\s+$/m', '', $output); 支持某些CJK页面。 - Soyoes

15

对我有用:

$output = str_replace(array("\r\n", "\r", "\n"), "", $output);

3
为什么在剥离\r和\n之前要先剥离\r\n?这样做是否有一定的速度优势,可以优先处理所有的\r\n组合式换行符? - Jimbo Jonny
3
@jimbo,我不确定是否有加速的好处。 - RayLoveless
我不得不为CodeIgniter中form_input()和其他表单帮助函数返回的HTML实现这个。这很完美地解决了问题。只替换\n就可以了。 - Zeeshan

5

您可以做:

$output = '<p>'.
              '<div class="title">Hello</div>'.
           '</p>';

这样一来,$output 就不会包含任何换行符。
这种方式也应该可行:
$output = preg_replace(array('/\r/', '/\n/'), '', $output);

我目前正在使用第一种方法,但希望使用更高效的东西。 - mrN
顺便提一下,你的代码出现了错误 preg_replace() [function.preg-replace]: Delimiter must not be alphanumeric or backslash - mrN
没错,我修复了这个问题...但是你会在preg_replace方法中遇到空格的问题。 - krtek
1
对于这样简单的替换,请使用 str_replace,而不是 preg。 - Flo
@Flo,str_replace 没有任何变化。 - mrN
请将以下与编程有关的内容从英语翻译成中文。只返回翻译后的文本: - Flo

3
$output = preg_replace('!\s+!m', ' ', $output);

我不会使用这个,因为它将' \n\n\n'替换为三个空格。如果你需要通过JavaScript在你的HTML代码中插入空格或制表符,它可能会导致意想不到的结果。 - mgutt

1

这个问题已经得到了很好的回答,但你可能可以做更多的事情,而不仅仅是修剪每行两端的空格:

  1. 首先提取引号内的所有文本(您不想触摸这些),用序列号标记替换,将序列号与文本一起存储
  2. 提取所有在 <script></script> 标签中的文本,并执行与步骤#1相同的操作
  3. 将所有空格(包括 \n、\r)替换为一个空格
  4. 将所有 >1 个空格序列替换为 1 个空格
  5. 将所有 >_< 替换为 >< (_ = 空格)
  6. 将所有 _><_</_ 替换为 ><</ (_ = 空格)
  7. 用实际文本替换标记

此过程可以潜在地压缩整个 HTML 文件。这利用了 HTML 标签内部的多个空白文本被解释为单个空格的事实。


0

这是以上函数的改进版。它添加了文本区域保护,并且任何标签都不会被修改。

我还删除了循环中的strlen(它是静态的)。

这可能会更快地运行,作为一个一次性过滤器来检查任何受保护的部分。对于如此小的protected_parts数组,它比四次循环遍历$str更有效率。

此外,这并不能修复:class = ""(等号和“)”之间的额外空格,因为它们是标签内的内容。

function MinifyHTML($str) {
$protected_parts = array('<pre>,</pre>','<textarea>,</textarea>', '<,>');
$extracted_values = array();
$i = 0;
foreach ($protected_parts as $part) {
    $finished = false;
    $search_offset = $first_offset = 0;
    $end_offset = 1;
    $startend = explode(',', $part);
    if (count($startend) === 1) $startend[1] = $startend[0];
    $len0 = strlen($startend[0]); $len1 = strlen($startend[1]);
    while ($finished === false) {
        $first_offset = strpos($str, $startend[0], $search_offset);

        if ($first_offset === false) $finished = true;
        else {
            $search_offset = strpos($str, $startend[1], $first_offset + $len0);
            $extracted_values[$i] = substr($str, $first_offset + $len0, $search_offset - $first_offset - $len0);
            $str = substr($str, 0, $first_offset + $len0).'$$#'.$i.'$$'.substr($str, $search_offset);
            $search_offset += $len1 + strlen((string)$i) + 5 - strlen($extracted_values[$i]);
            ++$i;
        }
    }
}
$str = preg_replace("/\s/", " ", $str);
$str = preg_replace("/\s{2,}/", " ", $str);
$replace = array('> <'=>'><', ' >'=>'>','< '=>'<','</ '=>'</');
$str = str_replace(array_keys($replace), array_values($replace), $str);

for ($d = 0; $d < $i; ++$d)
    $str = str_replace('$$#'.$d.'$$', $extracted_values[$d], $str);

return $str;
}

0

你不能在 <p> 标签内包含 <div> 标签 - 这是不符合规范的。

如果你不需要将其存储到变量中,你可以使用以下代码:

?><div><?php
    ?><div class="title">Hello</div><?php
?></div><?php

0

这是一个(据我测试)实现了Stephen Chung的指令的工作版本。我对第五点并不完全信服,但还是包括了它。

将您想要保护的内容放入protected_parts数组中。按照您想要保护它们的顺序进行操作。如果起始位和结束位不同(如HTML标记),请使用逗号分隔它们。

此外,我不知道这是否是最优化的方法,但它对我有效,并且似乎相当快速。请随意改进等(如果您这样做,请告诉我!)

function MinifyHTML($str) {
    $protected_parts = array("<pre>,</pre>", "\"", "'");
    $extracted_values = array();
    $i = 0;

    foreach ($protected_parts as $part) {
        $finished = false;
        $search_offset = 0;
        $first_offset = 0;
        $startend = explode(",", $part);
        if (count($startend) == 1) { $startend[1] = $startend[0]; }

        while (!$finished) {
            $first_offset = strpos($str, $startend[0], $search_offset);
            if ($first_offset === false) { $finished = true; }
            else {
                $search_offset = strpos($str, $startend[1], $first_offset + strlen($startend[0]));
                $extracted_values[$i] = substr($str, $first_offset + strlen($startend[0]), $search_offset - $first_offset - strlen($startend[0]));
                $str = substr($str, 0, $first_offset + strlen($startend[0]))."$#".$i."$".substr($str, $search_offset);
                $search_offset += strlen($startend[1]) + strlen((string)$i) + 3 - strlen($extracted_values[$i]);
                $i++;
            }
        }
    }

    $str = preg_replace("/\s/", " ", $str);
    $str = preg_replace("/\s{2,}/", " ", $str);
    $str = str_replace("> <", "><", $str);
    $str = str_replace(" >", ">", $str);
    $str = str_replace("< ", "<", $str);
    $str = str_replace("</ ", "</", $str);

    for ($i = count($extracted_values); $i >= 0; $i--) {
        $str = str_replace("$#".$i."$", $extracted_values[$i], $str);
    }

    return $str;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接