自动从 html 中删除缩进、不需要的空格(缩小)

Posted

技术标签:

【中文标题】自动从 html 中删除缩进、不需要的空格(缩小)【英文标题】:automatically remove indentation, unneeded empty space from html (minify) 【发布时间】:2011-05-17 20:23:08 【问题描述】:

我有一个 asp.net-mvc 应用程序,当我查看页面的源代码时,我看到 html 是缩进的,有很多空白,

我想如果我删除所有这些空格,我的页面会变得更小(以 KB 为单位)

有人知道如何自动删除它们吗?

【问题讨论】:

您可能还对高性能网站的其他技术感兴趣:developer.yahoo.com/performance/rules.html 重复 - ***.com/questions/855526/… 这个问题已经在***上回答了两次。请参阅下面的链接。 Solution 1Solution 2 @David Little 有点意思,但在这里我得到了一个非常酷的 asp.net-mvc 解决方案,你在其中找不到 【参考方案1】:

取自http://madskristensen.net/post/A-whitespace-removal-HTTP-module-for-ASPNET-20.aspx。

[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = false)]
internal class WhiteSpaceFilterAttribute : ActionFilterAttribute

    public override void OnActionExecuting(ActionExecutingContext filterContext)

        filterContext.HttpContext.Response.Filter = new WhiteSpaceStream(filterContext.HttpContext.Response.Filter);
    


internal class WhiteSpaceStream : Stream

    private Stream m_sink;
    private static Regex m_regex = new Regex(@"(?<=[^])\t2,|(?<=[>])\s2,(?=[<])|(?<=[>])\s2,11(?=[<])|(?=[\n])\s2,");
    //private static Regex m_regex = new Regex(@"^\s+", RegexOptions.Multiline | RegexOptions.Compiled); 

    public WhiteSpaceStream(Stream sink)
    
        m_sink = sink;
    

    public override bool CanRead
    
        get  return true; 
    

    public override bool CanSeek
    
        get  return true; 
    

    public override bool CanWrite
    
        get  return true; 
    

    public override void Flush()
    
        m_sink.Flush();
    

    public override long Length
    
        get  return 0; 
    

    private long _position;
    public override long Position
    
        get  return _position; 
        set  _position = value; 
    

    public override int Read(byte[] buffer, int offset, int count)
    
        return m_sink.Read(buffer, offset, count);
    

    public override long Seek(long offset, SeekOrigin origin)
    
        return m_sink.Seek(offset, origin);
    

    public override void SetLength(long value)
    
        m_sink.SetLength(value);
    

    public override void Close()
    
        m_sink.Close();
    

    public override void Write(byte[] buffer, int offset, int count)
    
        byte[] data = new byte[count];
        Buffer.BlockCopy(buffer, offset, data, 0, count);
        string text = Encoding.Default.GetString(buffer);

        text = m_regex.Replace(text, string.Empty);

        byte[] outdata = System.Text.Encoding.Default.GetBytes(text);
        m_sink.Write(outdata, 0, outdata.GetLength(0));
    

【讨论】:

【参考方案2】:

我想推荐以下代码。它完美地工作(我在几个网站上使用它)并且比@David的版本更简单:

using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Mvc;

public class WhitespaceStrip : ActionFilterAttribute 
    public override void OnActionExecuting(
        ActionExecutingContext Context) 
        try 
            Context.HttpContext.Response.Filter = new WhitespaceFilter();
         catch (Exception) 
            //  Ignore
        ;
    


public class WhitespaceFilter : MemoryStream 
    private HttpResponse Response = HttpContext.Current.Response;
    private Stream Filter = null;

    private string Source = string.Empty;
    private string[] ContentTypes = new string[1] 
        "text/html"
    ;

    public WhitespaceFilter() 
        this.Filter = this.Response.Filter;
    

    public override void Write(
        byte[] Buffer,
        int Offset,
        int Count) 
        this.Source = Encoding.UTF8.GetString(Buffer);

        if (this.ContentTypes.Contains(this.Response.ContentType)) 
            this.Response.ContentEncoding = Encoding.UTF8;

            this.Source = new Regex("(<pre>[^<>]*(((?<Open><)[^<>]*)+((?<Close-Open>>)[^<>]*)+)*(?(Open)(?!))</pre>)|\\s\\s+|[\\t\\n\\r]", RegexOptions.Compiled | RegexOptions.Singleline).Replace(this.Source, "$1");
            this.Source = new Regex("<!--.*?-->", RegexOptions.Compiled | RegexOptions.Singleline).Replace(this.Source, string.Empty);

            this.Filter.Write(Encoding.UTF8.GetBytes(this.Source), Offset, Encoding.UTF8.GetByteCount(this.Source));
         else 
            this.Filter.Write(Encoding.UTF8.GetBytes(this.Source), Offset, Encoding.UTF8.GetByteCount(this.Source));
        ;
    

更新

@Omu,只是因为当你说它慢 “6x” 时让我很生气,所以我开始看看你是否正确。我最终重新编写了过滤器并对其进行了一些清理,然后我运行了一些测试,在其中循环了一个表 10,000 以生成一些空白区域并查看过滤器是如何工作的。说了这么多,我发现这两个正则表达式完全没有区别。

现在,如果您暗示表达式的工作方式不同并且我的会变慢,那么也许这有一些道理,但要让您看到任何差异,您必须推出更多1 MB 大小的 HTML 页面...我希望这不是你正在做的。

此外,我的表达式保留了&lt;pre&gt; 元素中的空白...

说了这么多,这是我的修改版:

using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Mvc;

[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = false)]
internal class WhitespaceStripAttribute : ActionFilterAttribute 
    public override void OnActionExecuted(
        ActionExecutedContext ActionExecutedContext) 
        ActionExecutedContext.HttpContext.Response.Filter = new WhitespaceStream(ActionExecutedContext.HttpContext);
    


internal class WhitespaceStream : MemoryStream 
    private readonly HttpContextBase HttpContext = null;
    private readonly Stream FilterStream = null;

    private readonly string[] ContentTypes = new string[1] 
        "text/html"
    ;

    private static Regex WhitespaceRegex = new Regex("(<pre>[^<>]*(((?<Open><)[^<>]*)+((?<Close-Open>>)[^<>]*)+)*(?(Open)(?!))</pre>)|\\s\\s+|[\\t\\n\\r]", RegexOptions.Singleline | RegexOptions.Compiled);
    private static Regex CommentsRegex = new Regex("<!--.*?-->", RegexOptions.Singleline | RegexOptions.Compiled);

    public WhitespaceStream(
        HttpContextBase HttpContext) 
        this.HttpContext = HttpContext;
        this.FilterStream = HttpContext.Response.Filter;
    

    public override void Write(
        byte[] Buffer,
        int Offset,
        int Count) 
        string Source = Encoding.UTF8.GetString(Buffer);

        if (this.ContentTypes.Any(
            ct =>
                (ct == this.HttpContext.Response.ContentType))) 
            this.HttpContext.Response.ContentEncoding = Encoding.UTF8;

            Source = WhitespaceRegex.Replace(Source, "$1");
            Source = CommentsRegex.Replace(Source, string.Empty);
        ;

        this.FilterStream.Write(Encoding.UTF8.GetBytes(Source), Offset, Encoding.UTF8.GetByteCount(Source));
    

【讨论】:

这很好,但它的工作速度慢了 6 倍,如果你有 cmets 和一些 html 布局,它可能会杀死 js 好吧,我不知道如何衡量它的性能,因为即使有所有数据库交互,我的页面通常也会在不到一秒的时间内加载......另外,最小化 HTML 的意义不仅要删除缩进和空白,还要删除 cmets,这些字节是发送的额外字节,对浏览器和用户都没有用,而且从未见过。现在,如果您直接将 javascript 嵌入其中,那么这是一种不好的做法,我无法帮助您。不确定您所说的 “一些 html 布局”... 是什么意思 并非所有 cmets 都是无用的,有些可能包含必须作为使用条款一部分的版权信息。【参考方案3】:

在 HTML 中,多个空格被视为一个,您可以在响应中使用正则表达式:

/\s+/ /g

将任何连续的空格转换为单个空格。

请注意,虽然这会减小未压缩页面的大小,但如果您对页面进行 gzip 压缩,则节省的空间不会很大。

警告:这可能会破坏内联 JavaScript,因为 JS 将结束行视为命令分隔符(即,像 ;)。如果你的 JS 使用; 来分隔命令(大多数 JS 都这样做),你应该没问题。

另外,code samples in &lt;pre&gt; blocks 也会受到影响,因为那里会显示空格:

some   code   here 
  more          code 

变成

some code here  more code 

【讨论】:

以上是关于自动从 html 中删除缩进、不需要的空格(缩小)的主要内容,如果未能解决你的问题,请参考以下文章

eclipse基本设置----中文乱码行数显示缩进方式行末空格和空行自动删除常用注解

idea为啥空格是选择

webstorm退格与缩进问题

从 JSON 字符串中删除所有缩进和空格,除了它在 Ruby 中的值之外

解决IDEA中的CTRL+/ 快捷注释键不自动缩进

word自动目录,目录编号后面有空格,怎样设置能去掉?